<!DOCTYPE html>
<html lang="en">





<head>
  <meta charset="UTF-8">
  <link rel="apple-touch-icon" sizes="76x76" href="/img/favicon.jpg">
  <link rel="icon" type="image/png" href="/img/favicon.jpg">
  <meta name="viewport"
        content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no, shrink-to-fit=no">
  <meta http-equiv="x-ua-compatible" content="ie=edge">
  
  <meta name="theme-color" content="#2f4154">
  <meta name="description" content="">
  <meta name="author" content="John Doe">
  <meta name="keywords" content="">
  <title>Java数据结构与算法 - Nyima&#39;s Blog</title>

  <link  rel="stylesheet" href="https://cdn.staticfile.org/twitter-bootstrap/4.4.1/css/bootstrap.min.css" />


  <link  rel="stylesheet" href="https://cdn.staticfile.org/github-markdown-css/4.0.0/github-markdown.min.css" />
  <link  rel="stylesheet" href="/lib/hint/hint.min.css" />

  
    <link  rel="stylesheet" href="https://cdn.staticfile.org/highlight.js/10.0.0/styles/github-gist.min.css" />
  

  


<!-- 主题依赖的图标库，不要自行修改 -->

<link rel="stylesheet" href="//at.alicdn.com/t/font_1749284_yg9cfy8wd6.css">



<link rel="stylesheet" href="//at.alicdn.com/t/font_1736178_pjno9b9zyxs.css">


<link  rel="stylesheet" href="/css/main.css" />

<!-- 自定义样式保持在最底部 -->


  <script  src="/js/utils.js" ></script>
<meta name="generator" content="Hexo 4.2.1"></head>


<body>
  <header style="height: 70vh;">
    <nav id="navbar" class="navbar fixed-top  navbar-expand-lg navbar-dark scrolling-navbar">
  <div class="container">
    <a class="navbar-brand"
       href="/">&nbsp;<strong>Nyima</strong>&nbsp;</a>

    <button id="navbar-toggler-btn" class="navbar-toggler" type="button" data-toggle="collapse"
            data-target="#navbarSupportedContent"
            aria-controls="navbarSupportedContent" aria-expanded="false" aria-label="Toggle navigation">
      <div class="animated-icon"><span></span><span></span><span></span></div>
    </button>

    <!-- Collapsible content -->
    <div class="collapse navbar-collapse" id="navbarSupportedContent">
      <ul class="navbar-nav ml-auto text-center">
        
          
          
          
          
            <li class="nav-item">
              <a class="nav-link" href="/">
                <i class="iconfont icon-home-fill"></i>
                Home
              </a>
            </li>
          
        
          
          
          
          
            <li class="nav-item">
              <a class="nav-link" href="/archives/">
                <i class="iconfont icon-archive-fill"></i>
                Archives
              </a>
            </li>
          
        
          
          
          
          
            <li class="nav-item">
              <a class="nav-link" href="/categories/">
                <i class="iconfont icon-category-fill"></i>
                Categories
              </a>
            </li>
          
        
          
          
          
          
            <li class="nav-item">
              <a class="nav-link" href="/tags/">
                <i class="iconfont icon-tags-fill"></i>
                Tags
              </a>
            </li>
          
        
          
          
          
          
            <li class="nav-item">
              <a class="nav-link" href="/links/">
                <i class="iconfont icon-link-fill"></i>
                Links
              </a>
            </li>
          
        
          
          
          
          
            <li class="nav-item">
              <a class="nav-link" href="/about/">
                <i class="iconfont icon-user-fill"></i>
                About
              </a>
            </li>
          
        
        
          <li class="nav-item" id="search-btn">
            <a class="nav-link" data-toggle="modal" data-target="#modalSearch">&nbsp;&nbsp;<i
                class="iconfont icon-search"></i>&nbsp;&nbsp;</a>
          </li>
        
      </ul>
    </div>
  </div>
</nav>

    <div class="view intro-2" id="background" parallax=true
         style="background: url('/img/3.jpg') no-repeat center center;
           background-size: cover;">
      <div class="full-bg-img">
        <div class="mask flex-center" style="background-color: rgba(0, 0, 0, 0.3)">
          <div class="container text-center white-text fadeInUp">
            <span class="h2" id="subtitle">
              
            </span>

            
              
  <div class="mt-3 post-meta">
    <i class="iconfont icon-date-fill" aria-hidden="true"></i>
    <time datetime="2020-06-17 10:00">
      June 17, 2020 am
    </time>
  </div>


<div class="mt-1">
  
    
    <span class="post-meta mr-2">
      <i class="iconfont icon-chart"></i>
      33k 字
    </span>
  

  
    
    <span class="post-meta mr-2">
      <i class="iconfont icon-clock-fill"></i>
      
      
      450
       分钟
    </span>
  

  
  
</div>

            
          </div>

          
        </div>
      </div>
    </div>
  </header>

  <main>
    
      

<div class="container-fluid">
  <div class="row">
    <div class="d-none d-lg-block col-lg-2"></div>
    <div class="col-lg-8 nopadding-md">
      <div class="container nopadding-md" id="board-ctn">
        <div class="py-5" id="board">
          <div class="post-content mx-auto" id="post">
            
            <article class="markdown-body">
              <h1 id="Java数据结构与算法"><a href="#Java数据结构与算法" class="headerlink" title="Java数据结构与算法"></a>Java数据结构与算法</h1><p>该博客是根据<a href="https://www.bilibili.com/video/BV1B4411H76f?from=search&seid=14863448557523728830" target="_blank" rel="noopener">Java -韩顺平 图解Java 数据结构 和 算法-尚硅谷</a>学习时，所做的笔记</p>
<h1 id="一、稀疏数组和队列"><a href="#一、稀疏数组和队列" class="headerlink" title="一、稀疏数组和队列"></a>一、稀疏数组和队列</h1><h2 id="1、稀疏数组"><a href="#1、稀疏数组" class="headerlink" title="1、稀疏数组"></a>1、稀疏数组</h2><h3 id="基本功能"><a href="#基本功能" class="headerlink" title="基本功能"></a>基本功能</h3><p>当一个数组中大部分元素为０，或者为同一个值的数组时，可以使用<strong>稀疏数组</strong>来保存该数组。</p>
<h3 id="处理方法"><a href="#处理方法" class="headerlink" title="处理方法"></a>处理方法</h3><ul>
<li>记录数组<strong>一共有几行几列</strong>，有多少个<strong>不同的值</strong></li>
<li>把具有不同值的元素的行列及值记录在一个小规模的数组中，从而<strong>缩小程序</strong>的规模</li>
</ul>
<p><img src="https://nyimapicture.oss-cn-beijing.aliyuncs.com/img/20200610224442.png" srcset="/img/loading.gif" alt=""></p>
<p>如图，把一个6X7的二维数组变为了一个9X3的稀疏数组。其中</p>
<ul>
<li>第一行保存的是原二维数组的行、列以及非0值的个数</li>
<li>第二到九行保存的是每个非0值所在的位置及其数值</li>
</ul>
<h3 id="转换思路"><a href="#转换思路" class="headerlink" title="转换思路"></a>转换思路</h3><p>二维数组转稀疏数组</p>
<ul>
<li>遍历二维数组，得到二维数组中有效值的个数sum</li>
<li>创建稀疏数组，有sum+1行，3列（固定）</li>
<li>将二维数组中的有效值存入稀疏数组中</li>
</ul>
<p>稀疏数组转二维数组</p>
<ul>
<li>先读取稀疏数组的第一行（保存二维数组的行列信息），还原二维数组</li>
<li>读取稀疏数组的其他行，将值赋给二维数组的对应位置上的数</li>
</ul>
<p><strong>代码</strong></p>
<pre><code class="hljs java"><span class="hljs-keyword">public</span> <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">Demo2</span> </span>&#123;
   <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">static</span> <span class="hljs-keyword">void</span> <span class="hljs-title">main</span><span class="hljs-params">(String[] args)</span> </span>&#123;
      <span class="hljs-comment">//创建一个二维数组</span>
      <span class="hljs-keyword">int</span>[][] arr1 = <span class="hljs-keyword">new</span> <span class="hljs-keyword">int</span>[<span class="hljs-number">11</span>][<span class="hljs-number">11</span>];
      <span class="hljs-comment">//向二维数组里放值</span>
      arr1[<span class="hljs-number">1</span>][<span class="hljs-number">2</span>] = <span class="hljs-number">1</span>;
      arr1[<span class="hljs-number">2</span>][<span class="hljs-number">3</span>] = <span class="hljs-number">2</span>;
      arr1[<span class="hljs-number">3</span>][<span class="hljs-number">4</span>] = <span class="hljs-number">3</span>;

      <span class="hljs-comment">//打印二维数组</span>
      System.out.println(<span class="hljs-string">"遍历二维数组"</span>);
      <span class="hljs-keyword">for</span> (<span class="hljs-keyword">int</span> i = <span class="hljs-number">0</span>; i &lt; arr1.length; i++) &#123;
         <span class="hljs-keyword">for</span> (<span class="hljs-keyword">int</span> j = <span class="hljs-number">0</span>; j &lt; arr1[<span class="hljs-number">0</span>].length; j++) &#123;
            System.out.print(arr1[i][j] + <span class="hljs-string">"   "</span>);
         &#125;
         System.out.println();
      &#125;

      <span class="hljs-comment">//二位数组-----&gt;稀疏数组</span>
      <span class="hljs-comment">//遍历二维数组中有效值的个数,用sum来记录</span>
      <span class="hljs-keyword">int</span> sum = <span class="hljs-number">0</span>;
      <span class="hljs-keyword">for</span> (<span class="hljs-keyword">int</span> i = <span class="hljs-number">0</span>; i &lt; arr1.length; i++) &#123;
         <span class="hljs-keyword">for</span> (<span class="hljs-keyword">int</span> j = <span class="hljs-number">0</span>; j &lt; arr1[<span class="hljs-number">0</span>].length; j++) &#123;
            <span class="hljs-keyword">if</span> (arr1[i][j] != <span class="hljs-number">0</span>) &#123;
               <span class="hljs-comment">//二维数组中元素不为0即为有效值</span>
               sum++;
            &#125;
         &#125;
      &#125;

      <span class="hljs-comment">//创建稀疏数组</span>
      <span class="hljs-comment">//行数为sum+1，第一行用于保存二维数组的行列及有效值个数，列数固定为3</span>
      <span class="hljs-keyword">int</span>[][] sparseArr = <span class="hljs-keyword">new</span> <span class="hljs-keyword">int</span>[sum + <span class="hljs-number">1</span>][<span class="hljs-number">3</span>];
      <span class="hljs-comment">//存入二维数组的行列及有效值个数</span>
      sparseArr[<span class="hljs-number">0</span>][<span class="hljs-number">0</span>] = arr1.length;
      sparseArr[<span class="hljs-number">0</span>][<span class="hljs-number">1</span>] = arr1[<span class="hljs-number">0</span>].length;
      sparseArr[<span class="hljs-number">0</span>][<span class="hljs-number">2</span>] = sum;

      <span class="hljs-comment">//再次遍历二维数组，将有效值存入稀疏数组</span>
      <span class="hljs-comment">//用于保存稀疏数组的行数</span>
      <span class="hljs-keyword">int</span> count = <span class="hljs-number">1</span>;
      <span class="hljs-keyword">for</span> (<span class="hljs-keyword">int</span> i = <span class="hljs-number">0</span>; i &lt; arr1.length; i++) &#123;
         <span class="hljs-keyword">for</span> (<span class="hljs-keyword">int</span> j = <span class="hljs-number">0</span>; j &lt; arr1[<span class="hljs-number">0</span>].length; j++) &#123;
            <span class="hljs-keyword">if</span> (arr1[i][j] != <span class="hljs-number">0</span>) &#123;
               <span class="hljs-comment">//将值存入稀疏数组</span>
               sparseArr[count][<span class="hljs-number">0</span>] = i;
               sparseArr[count][<span class="hljs-number">1</span>] = j;
               sparseArr[count][<span class="hljs-number">2</span>] = arr1[i][j];
               count++;
            &#125;
         &#125;
      &#125;

      <span class="hljs-comment">//打印稀疏数组</span>
      System.out.println(<span class="hljs-string">"遍历稀疏数组"</span>);
      <span class="hljs-keyword">for</span> (<span class="hljs-keyword">int</span> i = <span class="hljs-number">0</span>; i &lt; sparseArr.length; i++) &#123;
         <span class="hljs-keyword">for</span> (<span class="hljs-keyword">int</span> j = <span class="hljs-number">0</span>; j &lt; sparseArr[<span class="hljs-number">0</span>].length; j++) &#123;
            System.out.print(sparseArr[i][j] + <span class="hljs-string">"   "</span>);
         &#125;
         System.out.println();
      &#125;


      <span class="hljs-comment">//稀疏数组------&gt;二维数组</span>
      <span class="hljs-comment">//先得到二位数组的行列数</span>
      <span class="hljs-keyword">int</span> row = sparseArr[<span class="hljs-number">0</span>][<span class="hljs-number">0</span>];
      <span class="hljs-keyword">int</span> col = sparseArr[<span class="hljs-number">0</span>][<span class="hljs-number">1</span>];
      <span class="hljs-keyword">int</span>[][] arr2 = <span class="hljs-keyword">new</span> <span class="hljs-keyword">int</span>[row][col];

      <span class="hljs-comment">//遍历稀疏数组，同时给二维数组赋值</span>
      <span class="hljs-keyword">for</span> (<span class="hljs-keyword">int</span> i = <span class="hljs-number">1</span>; i &lt; sparseArr.length; i++) &#123;
         row = sparseArr[i][<span class="hljs-number">0</span>];
         col = sparseArr[i][<span class="hljs-number">1</span>];
         <span class="hljs-comment">//该位置上对应的值</span>
         <span class="hljs-keyword">int</span> val = sparseArr[i][<span class="hljs-number">2</span>];
         arr2[row][col] = val;
      &#125;

      <span class="hljs-comment">//打印二维数组</span>
      System.out.println(<span class="hljs-string">"遍历还原后的二维数组"</span>);
      <span class="hljs-keyword">for</span> (<span class="hljs-keyword">int</span> i = <span class="hljs-number">0</span>; i &lt; arr2.length; i++) &#123;
         <span class="hljs-keyword">for</span> (<span class="hljs-keyword">int</span> j = <span class="hljs-number">0</span>; j &lt; arr2[<span class="hljs-number">0</span>].length; j++) &#123;
            System.out.print(arr2[i][j] + <span class="hljs-string">"   "</span>);
         &#125;
         System.out.println();
      &#125;
   &#125;
&#125;</code></pre>

<p>运行结果</p>
<pre><code class="hljs angelscript">遍历二维数组
<span class="hljs-number">0</span>   <span class="hljs-number">0</span>   <span class="hljs-number">0</span>   <span class="hljs-number">0</span>   <span class="hljs-number">0</span>   <span class="hljs-number">0</span>   <span class="hljs-number">0</span>   <span class="hljs-number">0</span>   <span class="hljs-number">0</span>   <span class="hljs-number">0</span>   <span class="hljs-number">0</span>   
<span class="hljs-number">0</span>   <span class="hljs-number">0</span>   <span class="hljs-number">1</span>   <span class="hljs-number">0</span>   <span class="hljs-number">0</span>   <span class="hljs-number">0</span>   <span class="hljs-number">0</span>   <span class="hljs-number">0</span>   <span class="hljs-number">0</span>   <span class="hljs-number">0</span>   <span class="hljs-number">0</span>   
<span class="hljs-number">0</span>   <span class="hljs-number">0</span>   <span class="hljs-number">0</span>   <span class="hljs-number">2</span>   <span class="hljs-number">0</span>   <span class="hljs-number">0</span>   <span class="hljs-number">0</span>   <span class="hljs-number">0</span>   <span class="hljs-number">0</span>   <span class="hljs-number">0</span>   <span class="hljs-number">0</span>   
<span class="hljs-number">0</span>   <span class="hljs-number">0</span>   <span class="hljs-number">0</span>   <span class="hljs-number">0</span>   <span class="hljs-number">3</span>   <span class="hljs-number">0</span>   <span class="hljs-number">0</span>   <span class="hljs-number">0</span>   <span class="hljs-number">0</span>   <span class="hljs-number">0</span>   <span class="hljs-number">0</span>   
<span class="hljs-number">0</span>   <span class="hljs-number">0</span>   <span class="hljs-number">0</span>   <span class="hljs-number">0</span>   <span class="hljs-number">0</span>   <span class="hljs-number">0</span>   <span class="hljs-number">0</span>   <span class="hljs-number">0</span>   <span class="hljs-number">0</span>   <span class="hljs-number">0</span>   <span class="hljs-number">0</span>   
<span class="hljs-number">0</span>   <span class="hljs-number">0</span>   <span class="hljs-number">0</span>   <span class="hljs-number">0</span>   <span class="hljs-number">0</span>   <span class="hljs-number">0</span>   <span class="hljs-number">0</span>   <span class="hljs-number">0</span>   <span class="hljs-number">0</span>   <span class="hljs-number">0</span>   <span class="hljs-number">0</span>   
<span class="hljs-number">0</span>   <span class="hljs-number">0</span>   <span class="hljs-number">0</span>   <span class="hljs-number">0</span>   <span class="hljs-number">0</span>   <span class="hljs-number">0</span>   <span class="hljs-number">0</span>   <span class="hljs-number">0</span>   <span class="hljs-number">0</span>   <span class="hljs-number">0</span>   <span class="hljs-number">0</span>   
<span class="hljs-number">0</span>   <span class="hljs-number">0</span>   <span class="hljs-number">0</span>   <span class="hljs-number">0</span>   <span class="hljs-number">0</span>   <span class="hljs-number">0</span>   <span class="hljs-number">0</span>   <span class="hljs-number">0</span>   <span class="hljs-number">0</span>   <span class="hljs-number">0</span>   <span class="hljs-number">0</span>   
<span class="hljs-number">0</span>   <span class="hljs-number">0</span>   <span class="hljs-number">0</span>   <span class="hljs-number">0</span>   <span class="hljs-number">0</span>   <span class="hljs-number">0</span>   <span class="hljs-number">0</span>   <span class="hljs-number">0</span>   <span class="hljs-number">0</span>   <span class="hljs-number">0</span>   <span class="hljs-number">0</span>   
<span class="hljs-number">0</span>   <span class="hljs-number">0</span>   <span class="hljs-number">0</span>   <span class="hljs-number">0</span>   <span class="hljs-number">0</span>   <span class="hljs-number">0</span>   <span class="hljs-number">0</span>   <span class="hljs-number">0</span>   <span class="hljs-number">0</span>   <span class="hljs-number">0</span>   <span class="hljs-number">0</span>   
<span class="hljs-number">0</span>   <span class="hljs-number">0</span>   <span class="hljs-number">0</span>   <span class="hljs-number">0</span>   <span class="hljs-number">0</span>   <span class="hljs-number">0</span>   <span class="hljs-number">0</span>   <span class="hljs-number">0</span>   <span class="hljs-number">0</span>   <span class="hljs-number">0</span>   <span class="hljs-number">0</span>   
遍历稀疏数组
<span class="hljs-number">11</span>   <span class="hljs-number">11</span>   <span class="hljs-number">3</span>   
<span class="hljs-number">1</span>   <span class="hljs-number">2</span>   <span class="hljs-number">1</span>   
<span class="hljs-number">2</span>   <span class="hljs-number">3</span>   <span class="hljs-number">2</span>   
<span class="hljs-number">3</span>   <span class="hljs-number">4</span>   <span class="hljs-number">3</span>   
遍历还原后的二维数组
<span class="hljs-number">0</span>   <span class="hljs-number">0</span>   <span class="hljs-number">0</span>   <span class="hljs-number">0</span>   <span class="hljs-number">0</span>   <span class="hljs-number">0</span>   <span class="hljs-number">0</span>   <span class="hljs-number">0</span>   <span class="hljs-number">0</span>   <span class="hljs-number">0</span>   <span class="hljs-number">0</span>   
<span class="hljs-number">0</span>   <span class="hljs-number">0</span>   <span class="hljs-number">1</span>   <span class="hljs-number">0</span>   <span class="hljs-number">0</span>   <span class="hljs-number">0</span>   <span class="hljs-number">0</span>   <span class="hljs-number">0</span>   <span class="hljs-number">0</span>   <span class="hljs-number">0</span>   <span class="hljs-number">0</span>   
<span class="hljs-number">0</span>   <span class="hljs-number">0</span>   <span class="hljs-number">0</span>   <span class="hljs-number">2</span>   <span class="hljs-number">0</span>   <span class="hljs-number">0</span>   <span class="hljs-number">0</span>   <span class="hljs-number">0</span>   <span class="hljs-number">0</span>   <span class="hljs-number">0</span>   <span class="hljs-number">0</span>   
<span class="hljs-number">0</span>   <span class="hljs-number">0</span>   <span class="hljs-number">0</span>   <span class="hljs-number">0</span>   <span class="hljs-number">3</span>   <span class="hljs-number">0</span>   <span class="hljs-number">0</span>   <span class="hljs-number">0</span>   <span class="hljs-number">0</span>   <span class="hljs-number">0</span>   <span class="hljs-number">0</span>   
<span class="hljs-number">0</span>   <span class="hljs-number">0</span>   <span class="hljs-number">0</span>   <span class="hljs-number">0</span>   <span class="hljs-number">0</span>   <span class="hljs-number">0</span>   <span class="hljs-number">0</span>   <span class="hljs-number">0</span>   <span class="hljs-number">0</span>   <span class="hljs-number">0</span>   <span class="hljs-number">0</span>   
<span class="hljs-number">0</span>   <span class="hljs-number">0</span>   <span class="hljs-number">0</span>   <span class="hljs-number">0</span>   <span class="hljs-number">0</span>   <span class="hljs-number">0</span>   <span class="hljs-number">0</span>   <span class="hljs-number">0</span>   <span class="hljs-number">0</span>   <span class="hljs-number">0</span>   <span class="hljs-number">0</span>   
<span class="hljs-number">0</span>   <span class="hljs-number">0</span>   <span class="hljs-number">0</span>   <span class="hljs-number">0</span>   <span class="hljs-number">0</span>   <span class="hljs-number">0</span>   <span class="hljs-number">0</span>   <span class="hljs-number">0</span>   <span class="hljs-number">0</span>   <span class="hljs-number">0</span>   <span class="hljs-number">0</span>   
<span class="hljs-number">0</span>   <span class="hljs-number">0</span>   <span class="hljs-number">0</span>   <span class="hljs-number">0</span>   <span class="hljs-number">0</span>   <span class="hljs-number">0</span>   <span class="hljs-number">0</span>   <span class="hljs-number">0</span>   <span class="hljs-number">0</span>   <span class="hljs-number">0</span>   <span class="hljs-number">0</span>   
<span class="hljs-number">0</span>   <span class="hljs-number">0</span>   <span class="hljs-number">0</span>   <span class="hljs-number">0</span>   <span class="hljs-number">0</span>   <span class="hljs-number">0</span>   <span class="hljs-number">0</span>   <span class="hljs-number">0</span>   <span class="hljs-number">0</span>   <span class="hljs-number">0</span>   <span class="hljs-number">0</span>   
<span class="hljs-number">0</span>   <span class="hljs-number">0</span>   <span class="hljs-number">0</span>   <span class="hljs-number">0</span>   <span class="hljs-number">0</span>   <span class="hljs-number">0</span>   <span class="hljs-number">0</span>   <span class="hljs-number">0</span>   <span class="hljs-number">0</span>   <span class="hljs-number">0</span>   <span class="hljs-number">0</span>   
<span class="hljs-number">0</span>   <span class="hljs-number">0</span>   <span class="hljs-number">0</span>   <span class="hljs-number">0</span>   <span class="hljs-number">0</span>   <span class="hljs-number">0</span>   <span class="hljs-number">0</span>   <span class="hljs-number">0</span>   <span class="hljs-number">0</span>   <span class="hljs-number">0</span>   <span class="hljs-number">0</span></code></pre>



<h2 id="2、队列"><a href="#2、队列" class="headerlink" title="2、队列"></a>2、队列</h2><h3 id="定义"><a href="#定义" class="headerlink" title="定义"></a>定义</h3><ul>
<li>队列是一个<strong>有序列表</strong>，可以用<strong>数组</strong>或是<strong>链表</strong>来实现。</li>
<li>遵循<strong>先入先出</strong>的原则。即：先存入队列的数据，要先取出。后存入的要后取出</li>
</ul>
<h3 id="模拟思路"><a href="#模拟思路" class="headerlink" title="模拟思路"></a>模拟思路</h3><ul>
<li><p>队列本身是有序列表，若使用数组的结构来存储队列的数据，则队列数组的声明如下图, 其中 maxSize 是该队列的最大容量</p>
</li>
<li><p>因为队列的输出、输入是分别从前后端来处理，因此需要两个变量 front及 rear分别记录队列前后端的下标，front 会随着数据输出而改变，而 rear则是随着数据输入而改变，如图所示</p>
</li>
</ul>
<p><img src="https://nyimapicture.oss-cn-beijing.aliyuncs.com/img/20200614170043.png" srcset="/img/loading.gif" alt=""></p>
<h4 id="入队出队操作模拟"><a href="#入队出队操作模拟" class="headerlink" title="入队出队操作模拟"></a>入队出队操作模拟</h4><p>当我们将数据存入队列时称为”addQueue”，addQueue 的处理需要有两个步骤：</p>
<ul>
<li><p>将尾指针往后移：rear+1 , 当 <strong>front == rear</strong> 时，队列为空</p>
</li>
<li><p>若尾指针 rear 小于队列的最大下标 maxSize-1，则将数据存入 rear所指的数组元素中，否则无法存入数据。<strong>rear == maxSize - 1</strong>时，队列满</p>
</li>
</ul>
<p><strong>注意</strong>：front指向的是队列首元素的<strong>前一个位置</strong></p>
<p><strong>实现代码</strong></p>
<pre><code class="hljs java"><span class="hljs-keyword">public</span> <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">Demo3</span> </span>&#123;
   <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">static</span> <span class="hljs-keyword">void</span> <span class="hljs-title">main</span><span class="hljs-params">(String[] args)</span> </span>&#123;
      ArrayQueue queue = <span class="hljs-keyword">new</span> ArrayQueue(<span class="hljs-number">5</span>);
      queue.addNum(<span class="hljs-number">1</span>);
      queue.addNum(<span class="hljs-number">2</span>);
      queue.addNum(<span class="hljs-number">3</span>);
      queue.addNum(<span class="hljs-number">4</span>);
      queue.addNum(<span class="hljs-number">5</span>);
      System.out.println(queue.getNum());
      queue.showQueue();
   &#125;
&#125;

<span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">ArrayQueue</span> </span>&#123;
   <span class="hljs-comment">//队列的大小</span>
   <span class="hljs-keyword">int</span> maxSize;
   <span class="hljs-comment">//用数组来实现队列</span>
   <span class="hljs-keyword">int</span>[] arr;
   <span class="hljs-comment">//指向队列首元素的前一个位置</span>
   <span class="hljs-keyword">int</span> front;
   <span class="hljs-comment">//指向队列的尾元素</span>
   <span class="hljs-keyword">int</span> rear;

   <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-title">ArrayQueue</span><span class="hljs-params">(<span class="hljs-keyword">int</span> maxSize)</span> </span>&#123;
      <span class="hljs-keyword">this</span>.maxSize = maxSize;
      arr = <span class="hljs-keyword">new</span> <span class="hljs-keyword">int</span>[<span class="hljs-keyword">this</span>.maxSize];
      <span class="hljs-comment">//front指向队列首元素的前一个位置</span>
      front = -<span class="hljs-number">1</span>;
      rear = -<span class="hljs-number">1</span>;
   &#125;


   <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">boolean</span> <span class="hljs-title">isFull</span><span class="hljs-params">()</span> </span>&#123;
      <span class="hljs-keyword">return</span> rear == maxSize - <span class="hljs-number">1</span>;
   &#125;


   <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">boolean</span> <span class="hljs-title">isEmpty</span><span class="hljs-params">()</span> </span>&#123;
      <span class="hljs-keyword">return</span> front == rear;
   &#125;


   <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">addNum</span><span class="hljs-params">(<span class="hljs-keyword">int</span> num)</span> </span>&#123;
      <span class="hljs-keyword">if</span>(isFull()) &#123;
         System.out.println(<span class="hljs-string">"队列已满，无法在进行入队操作"</span>);
         <span class="hljs-keyword">return</span>;
      &#125;
      <span class="hljs-comment">//队尾标记后移，指向要放入的元素的位置</span>
      rear++;
      arr[rear] = num;
   &#125;

   <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">int</span> <span class="hljs-title">getNum</span><span class="hljs-params">()</span> </span>&#123;
      <span class="hljs-keyword">if</span>(isEmpty()) &#123;
         <span class="hljs-keyword">throw</span> <span class="hljs-keyword">new</span> RuntimeException(<span class="hljs-string">"队列为空，无法出队"</span>);
      &#125;
      <span class="hljs-comment">//队首标记后移，指向队首元素</span>
      System.out.print(<span class="hljs-string">"出队元素是："</span>);
      front++;
      <span class="hljs-keyword">return</span> arr[front];
   &#125;

   <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">showQueue</span><span class="hljs-params">()</span> </span>&#123;
      <span class="hljs-keyword">if</span>(isEmpty()) &#123;
         <span class="hljs-keyword">throw</span> <span class="hljs-keyword">new</span> RuntimeException(<span class="hljs-string">"队列为空，无法遍历"</span>);
      &#125;
      System.out.println(<span class="hljs-string">"遍历队列"</span>);
      <span class="hljs-comment">//从front+1开始读取元素</span>
      <span class="hljs-keyword">for</span>(<span class="hljs-keyword">int</span> start = front+<span class="hljs-number">1</span>; start&lt;=rear; start++) &#123;
         System.out.println(arr[start]);
      &#125;
   &#125;
&#125;</code></pre>

<p>运行结果</p>
<pre><code class="hljs angelscript">出队元素是：<span class="hljs-number">1</span>
遍历队列
<span class="hljs-number">2</span>
<span class="hljs-number">3</span>
<span class="hljs-number">4</span>
<span class="hljs-number">5</span></code></pre>



<h3 id="环形队列"><a href="#环形队列" class="headerlink" title="环形队列"></a>环形队列</h3><p>思路：</p>
<ul>
<li>front变量指向<strong>队首元素</strong>，初值为0</li>
<li>rear变量指向队尾元素的<strong>下一个元素</strong>，初值为0。规定空出一个位置</li>
<li>队列为空的判定条件：front == rear</li>
<li>队列为满的判定条件：(rear + 1) % maxSize == front</li>
<li>队列中有效元素的个数：(rear - front + maxSize) % maxSize</li>
<li>入队和出队时，都需要让标记<strong>对maxSize取模</strong></li>
</ul>
<p><strong>代码</strong></p>
<pre><code class="hljs java"><span class="hljs-keyword">public</span> <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">Demo4</span> </span>&#123;
   <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">static</span> <span class="hljs-keyword">void</span> <span class="hljs-title">main</span><span class="hljs-params">(String[] args)</span> </span>&#123;
      ArrayAroundQueue aroundQueue = <span class="hljs-keyword">new</span> ArrayAroundQueue(<span class="hljs-number">5</span>);
      aroundQueue.addNum(<span class="hljs-number">1</span>);
      aroundQueue.addNum(<span class="hljs-number">2</span>);
      aroundQueue.addNum(<span class="hljs-number">3</span>);
      aroundQueue.addNum(<span class="hljs-number">4</span>);
      aroundQueue.showQueue();
      System.out.println(aroundQueue.getNum());
      System.out.println(aroundQueue.getNum());
      aroundQueue.addNum(<span class="hljs-number">5</span>);
      aroundQueue.addNum(<span class="hljs-number">6</span>);
      aroundQueue.showQueue();
      aroundQueue.getHead();
   &#125;
&#125;

<span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">ArrayAroundQueue</span> </span>&#123;
   <span class="hljs-comment">//队列的大小</span>
   <span class="hljs-keyword">int</span> maxSize;
   <span class="hljs-comment">//用数组来实现队列</span>
   <span class="hljs-keyword">int</span>[] arr;
   <span class="hljs-comment">//指向队列首元素的前一个位置</span>
   <span class="hljs-keyword">int</span> front;
   <span class="hljs-comment">//指向队列的尾元素</span>
   <span class="hljs-keyword">int</span> rear;

   <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-title">ArrayAroundQueue</span><span class="hljs-params">(<span class="hljs-keyword">int</span> maxSize)</span> </span>&#123;
      <span class="hljs-keyword">this</span>.maxSize = maxSize;
      arr = <span class="hljs-keyword">new</span> <span class="hljs-keyword">int</span>[<span class="hljs-keyword">this</span>.maxSize];
      <span class="hljs-comment">//front指向队列首元素的前一个位置</span>
      front = <span class="hljs-number">0</span>;
      rear = <span class="hljs-number">0</span>;
   &#125;


   <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">boolean</span> <span class="hljs-title">isFull</span><span class="hljs-params">()</span> </span>&#123;
      <span class="hljs-keyword">return</span> (rear+<span class="hljs-number">1</span>)%maxSize == front;
   &#125;


   <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">boolean</span> <span class="hljs-title">isEmpty</span><span class="hljs-params">()</span> </span>&#123;
      <span class="hljs-keyword">return</span> front == rear;
   &#125;


   <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">addNum</span><span class="hljs-params">(<span class="hljs-keyword">int</span> num)</span> </span>&#123;
      <span class="hljs-keyword">if</span>(isFull()) &#123;
         System.out.println(<span class="hljs-string">"队列已满，无法在进行入队操作"</span>);
         <span class="hljs-keyword">return</span>;
      &#125;
      <span class="hljs-comment">//先放入元素，在后移队尾标记</span>
      arr[rear] = num;
      rear = (rear+<span class="hljs-number">1</span>)%maxSize;
   &#125;

   <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">int</span> <span class="hljs-title">getNum</span><span class="hljs-params">()</span> </span>&#123;
      <span class="hljs-keyword">if</span>(isEmpty()) &#123;
         <span class="hljs-keyword">throw</span> <span class="hljs-keyword">new</span> RuntimeException(<span class="hljs-string">"队列为空，无法出队"</span>);
      &#125;
      <span class="hljs-comment">//队首标记后移，指向队首元素</span>
      System.out.print(<span class="hljs-string">"出队元素是："</span>);
      <span class="hljs-keyword">int</span> num = arr[front];
      front = (front+<span class="hljs-number">1</span>)%maxSize;
      <span class="hljs-keyword">return</span> num;
   &#125;

   <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">showQueue</span><span class="hljs-params">()</span> </span>&#123;
      <span class="hljs-keyword">if</span>(isEmpty()) &#123;
         <span class="hljs-keyword">throw</span> <span class="hljs-keyword">new</span> RuntimeException(<span class="hljs-string">"队列为空，无法遍历"</span>);
      &#125;
      System.out.println(<span class="hljs-string">"遍历队列"</span>);
      <span class="hljs-comment">//当front + 1 == rear时停止遍历</span>
      <span class="hljs-keyword">int</span> start = front;
      <span class="hljs-keyword">while</span>(start != rear) &#123;
         System.out.println(arr[start]);
         <span class="hljs-comment">//移动到下一个元素</span>
         start = (start+<span class="hljs-number">1</span>)%maxSize;
      &#125;
   &#125;

   <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">getHead</span><span class="hljs-params">()</span> </span>&#123;
      <span class="hljs-keyword">if</span>(isEmpty()) &#123;
         <span class="hljs-keyword">throw</span> <span class="hljs-keyword">new</span> RuntimeException(<span class="hljs-string">"队列为空"</span>);
      &#125;

      System.out.println(<span class="hljs-string">"队首元素为："</span>+arr[front]);
   &#125;
&#125;</code></pre>

<p>运行结果</p>
<pre><code class="hljs java">遍历队列
<span class="hljs-number">1</span>
<span class="hljs-number">2</span>
<span class="hljs-number">3</span>
<span class="hljs-number">4</span>
出队元素是：<span class="hljs-number">1</span>
出队元素是：<span class="hljs-number">2</span>
遍历队列
<span class="hljs-number">3</span>
<span class="hljs-number">4</span>
<span class="hljs-number">5</span>
<span class="hljs-number">6</span>
队首元素为：<span class="hljs-number">3</span></code></pre>



<h1 id="二、链表"><a href="#二、链表" class="headerlink" title="二、链表"></a>二、链表</h1><h2 id="1、单向链表"><a href="#1、单向链表" class="headerlink" title="1、单向链表"></a>1、单向链表</h2><h3 id="链表的介绍"><a href="#链表的介绍" class="headerlink" title="链表的介绍"></a>链表的介绍</h3><p>链表在内存中的存储</p>
<p><img src="https://nyimapicture.oss-cn-beijing.aliyuncs.com/img/20200617221622.png" srcset="/img/loading.gif" alt=""></p>
<p><strong>特点</strong></p>
<ul>
<li>链表是以节点的方式来存储,<strong>是链式存储</strong></li>
<li>每个节点包含 data 域 和 next 域。next域用来指向下一个节点</li>
<li>链表的各个节点不一定是连续存储的</li>
<li>链表分<strong>带头节点的链表</strong>和<strong>没有头节点的链表</strong>，根据实际的需求来确定</li>
</ul>
<p>带头结点的<strong>逻辑示意图</strong></p>
<p><img src="https://nyimapicture.oss-cn-beijing.aliyuncs.com/img/20200617221632.png" srcset="/img/loading.gif" alt=""></p>
<h3 id="实现思路"><a href="#实现思路" class="headerlink" title="实现思路"></a>实现思路</h3><p><strong>创建（添加）</strong></p>
<ul>
<li>先创建一个Head头节点，表示单链表的头</li>
<li>后面我们每添加一个节点，就放在链表的最后</li>
</ul>
<p><strong>遍历</strong></p>
<ul>
<li>通过一个辅助变量，来遍历整个链表</li>
</ul>
<p><strong>有序插入</strong></p>
<ul>
<li>先遍历链表，找到应该插入的位置</li>
<li>要插入的节点的next指向插入位置的后一个节点</li>
<li>插入位置的前一个节点的next指向要插入节点<ul>
<li>插入前要判断是否在队尾插入</li>
</ul>
</li>
</ul>
<p><strong>根据某个属性节点修改值</strong></p>
<ul>
<li>先遍历节点，找到修改的位置<ul>
<li>如果未找到修改节点，则不修改</li>
</ul>
</li>
</ul>
<p><strong>删除某个节点</strong></p>
<ul>
<li>先遍历节点，找到要删除节点的前一个节点</li>
<li>进行删除操作</li>
</ul>
<p><strong>求倒数第n个节点的信息</strong></p>
<ul>
<li>遍历链表，求出链表的<strong>有效长度</strong>length（不算头结点）</li>
<li>遍历链表到第length-n的节点</li>
</ul>
<p><strong>翻转链表</strong></p>
<p><img src="https://nyimapicture.oss-cn-beijing.aliyuncs.com/img/20200616112143.png" srcset="/img/loading.gif" alt=""></p>
<ul>
<li>创建一个新的头结点，作为新链表的头</li>
<li>从头遍历旧链表，将遍历到的节点插入新链表的头结点之后</li>
<li>注意需要用到<strong>两个暂存节点</strong><ul>
<li>一个用来保存正在遍历的节点</li>
<li>一个用来保存正在遍历节点的下一个节点</li>
</ul>
</li>
</ul>
<p><img src="https://nyimapicture.oss-cn-beijing.aliyuncs.com/img/20200616142843.png" srcset="/img/loading.gif" alt=""></p>
<p><img src="https://nyimapicture.oss-cn-beijing.aliyuncs.com/img/20200616142931.png" srcset="/img/loading.gif" alt=""></p>
<p><img src="https://nyimapicture.oss-cn-beijing.aliyuncs.com/img/20200616142248.png" srcset="/img/loading.gif" alt=""></p>
<p><img src="https://nyimapicture.oss-cn-beijing.aliyuncs.com/img/20200616142415.png" srcset="/img/loading.gif" alt=""></p>
<p><img src="https://nyimapicture.oss-cn-beijing.aliyuncs.com/img/20200617221646.png" srcset="/img/loading.gif" alt=""></p>
<p><strong>逆序打印</strong></p>
<ul>
<li>遍历链表，将遍历到的节点入栈</li>
<li>遍历完后，进行出栈操作，同时打印出栈元素</li>
</ul>
<p><strong>代码</strong></p>
<pre><code class="hljs java"><span class="hljs-keyword">public</span> <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">Demo1</span> </span>&#123;
	<span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">static</span> <span class="hljs-keyword">void</span> <span class="hljs-title">main</span><span class="hljs-params">(String[] args)</span> </span>&#123;
		LinkedList linkedList = <span class="hljs-keyword">new</span> LinkedList();
		linkedList.traverseNode();
		System.out.println();
		<span class="hljs-comment">//创建学生节点，并插入链表</span>
		StudentNode student1 = <span class="hljs-keyword">new</span> StudentNode(<span class="hljs-number">1</span>, <span class="hljs-string">"Nyima"</span>);
		StudentNode student3 = <span class="hljs-keyword">new</span> StudentNode(<span class="hljs-number">3</span>, <span class="hljs-string">"Lulu"</span>);
		linkedList.addNode(student1);
		linkedList.addNode(student3);
		linkedList.traverseNode();
		System.out.println();

		<span class="hljs-comment">//按id大小插入</span>
		System.out.println(<span class="hljs-string">"有序插入"</span>);
		StudentNode student2 = <span class="hljs-keyword">new</span> StudentNode(<span class="hljs-number">0</span>, <span class="hljs-string">"Wenwen"</span>);
		linkedList.addByOrder(student2);
		linkedList.traverseNode();
		System.out.println();

		<span class="hljs-comment">//按id修改学生信息</span>
		System.out.println(<span class="hljs-string">"修改学生信息"</span>);
		student2 = <span class="hljs-keyword">new</span> StudentNode(<span class="hljs-number">1</span>, <span class="hljs-string">"Hulu"</span>);
		linkedList.changeNode(student2);
		linkedList.traverseNode();
		System.out.println();

		<span class="hljs-comment">//根据id删除学生信息</span>
		System.out.println(<span class="hljs-string">"删除学生信息"</span>);
		student2 = <span class="hljs-keyword">new</span> StudentNode(<span class="hljs-number">1</span>, <span class="hljs-string">"Hulu"</span>);
		linkedList.deleteNode(student2);
		linkedList.traverseNode();
		System.out.println();

		<span class="hljs-comment">//获得倒数第几个节点</span>
		System.out.println(<span class="hljs-string">"获得倒数节点"</span>);
		System.out.println(linkedList.getStuByRec(<span class="hljs-number">2</span>));
		System.out.println();

		<span class="hljs-comment">//翻转链表</span>
		System.out.println(<span class="hljs-string">"翻转链表"</span>);
		LinkedList newLinkedList = linkedList.reverseList();
		newLinkedList.traverseNode();
		System.out.println();

		<span class="hljs-comment">//倒叙遍历链表</span>
		System.out.println(<span class="hljs-string">"倒序遍历链表"</span>);
		newLinkedList.reverseTraverse();

	&#125;
&#125;

<span class="hljs-comment">/**</span>
<span class="hljs-comment"> * 创建链表</span>
<span class="hljs-comment"> */</span>
<span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">LinkedList</span> </span>&#123;
	<span class="hljs-comment">//头节点，防止被修改，设置为私有的</span>
	<span class="hljs-keyword">private</span> StudentNode head = <span class="hljs-keyword">new</span> StudentNode(<span class="hljs-number">0</span>, <span class="hljs-string">""</span>);

	<span class="hljs-comment">/**</span>
<span class="hljs-comment">	 * 添加节点</span>
<span class="hljs-comment">	 * <span class="hljs-doctag">@param</span> node 要添加的节点</span>
<span class="hljs-comment">	 */</span>
	<span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">addNode</span><span class="hljs-params">(StudentNode node)</span> </span>&#123;
		<span class="hljs-comment">//因为头节点不能被修改，所以创建一个辅助节点</span>
		StudentNode temp = head;
		<span class="hljs-comment">//找到最后一个节点</span>
		<span class="hljs-keyword">while</span> (<span class="hljs-keyword">true</span>) &#123;
			<span class="hljs-comment">//temp是尾节点就停止循环</span>
			<span class="hljs-keyword">if</span>(temp.next == <span class="hljs-keyword">null</span>) &#123;
				<span class="hljs-keyword">break</span>;
			&#125;
			<span class="hljs-comment">//不是尾结点就向后移动</span>
			temp = temp.next;
		&#125;
		<span class="hljs-comment">//现在temp是尾节点了，再次插入</span>
		temp.next = node;
	&#125;

	<span class="hljs-comment">/**</span>
<span class="hljs-comment">	 * 遍历链表</span>
<span class="hljs-comment">	 */</span>
	<span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">traverseNode</span><span class="hljs-params">()</span> </span>&#123;
		System.out.println(<span class="hljs-string">"开始遍历链表"</span>);
		<span class="hljs-keyword">if</span>(head.next == <span class="hljs-keyword">null</span>) &#123;
			System.out.println(<span class="hljs-string">"链表为空"</span>);
		&#125;
		<span class="hljs-comment">//创建辅助节点</span>
		StudentNode temp = head.next;
		<span class="hljs-keyword">while</span>(<span class="hljs-keyword">true</span>) &#123;
			<span class="hljs-comment">//遍历完成就停止循环</span>
			<span class="hljs-keyword">if</span>(temp == <span class="hljs-keyword">null</span>) &#123;
				<span class="hljs-keyword">break</span>;
			&#125;
			System.out.println(temp);
			temp = temp.next;
		&#125;
	&#125;

	<span class="hljs-comment">/**</span>
<span class="hljs-comment">	 * 按id顺序插入节点</span>
<span class="hljs-comment">	 * <span class="hljs-doctag">@param</span> node</span>
<span class="hljs-comment">	 */</span>
	<span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">addByOrder</span><span class="hljs-params">(StudentNode node)</span> </span>&#123;
		<span class="hljs-comment">//如果没有首节点，就直接插入</span>
		<span class="hljs-keyword">if</span>(head.next == <span class="hljs-keyword">null</span>) &#123;
			head.next = node;
			<span class="hljs-keyword">return</span>;
		&#125;
		<span class="hljs-comment">//辅助节点，用于找到插入位置和插入操作</span>
		StudentNode temp = head;
		<span class="hljs-comment">//节点的下一个节点存在，且它的id小于要插入节点的id，就继续下移</span>
		<span class="hljs-keyword">while</span> (temp.next!=<span class="hljs-keyword">null</span> &amp;&amp; temp.next.id &lt; node.id) &#123;
			temp = temp.next;
		&#125;
		<span class="hljs-comment">//如果temp的下一个节点存在，则执行该操作</span>
		<span class="hljs-comment">//且插入操作，顺序不能换</span>
		<span class="hljs-keyword">if</span>(temp.next != <span class="hljs-keyword">null</span>) &#123;
			node.next = temp.next;
		&#125;
		temp.next = node;
 	&#125;

	<span class="hljs-comment">/**</span>
<span class="hljs-comment">	 * 根据id来修改节点信息</span>
<span class="hljs-comment">	 * <span class="hljs-doctag">@param</span> node 修改信息的节点</span>
<span class="hljs-comment">	 */</span>
 	<span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">changeNode</span><span class="hljs-params">(StudentNode node)</span> </span>&#123;
		<span class="hljs-keyword">if</span>(head == <span class="hljs-keyword">null</span>) &#123;
			System.out.println(<span class="hljs-string">"链表为空，请先加入该学生信息"</span>);
			<span class="hljs-keyword">return</span>;
		&#125;
		StudentNode temp = head;
		<span class="hljs-comment">//遍历链表，找到要修改的节点</span>
		<span class="hljs-keyword">while</span> (temp.next!= <span class="hljs-keyword">null</span> &amp;&amp; temp.id != node.id) &#123;
			temp = temp.next;
		&#125;
		<span class="hljs-comment">//如果temp已经是最后一个节点，判断id是否相等</span>
		<span class="hljs-keyword">if</span>(temp.id != node.id) &#123;
			System.out.println(<span class="hljs-string">"未找到该学生的信息，请先创建该学生的信息"</span>);
			<span class="hljs-keyword">return</span>;
		&#125;
		<span class="hljs-comment">//修改学生信息</span>
		temp.name = node.name;
	&#125;

	<span class="hljs-comment">/**</span>
<span class="hljs-comment">	 * 根据id删除节点</span>
<span class="hljs-comment">	 * <span class="hljs-doctag">@param</span> node 要删除的节点</span>
<span class="hljs-comment">	 */</span>
	<span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">deleteNode</span><span class="hljs-params">(StudentNode node)</span> </span>&#123;
 		<span class="hljs-keyword">if</span>(head.next == <span class="hljs-keyword">null</span>) &#123;
			System.out.println(<span class="hljs-string">"链表为空"</span>);
			<span class="hljs-keyword">return</span>;
		&#125;
 		StudentNode temp = head.next;
 		<span class="hljs-comment">//遍历链表，找到要删除的节点</span>
 		<span class="hljs-keyword">if</span>(temp.next!=<span class="hljs-keyword">null</span> &amp;&amp; temp.next.id!=node.id) &#123;
 			temp = temp.next;
		&#125;
 		<span class="hljs-comment">//判断最后一个节点的是否要删除的节点</span>
 		<span class="hljs-keyword">if</span>(temp.next.id != node.id) &#123;
			System.out.println(<span class="hljs-string">"请先插入该学生信息"</span>);
			<span class="hljs-keyword">return</span>;
		&#125;
 		<span class="hljs-comment">//删除该节点</span>
 		temp.next = temp.next.next;
	&#125;

	<span class="hljs-comment">/**</span>
<span class="hljs-comment">	 * 得到倒数的节点</span>
<span class="hljs-comment">	 * <span class="hljs-doctag">@param</span> index 倒数第几个数</span>
<span class="hljs-comment">	 * <span class="hljs-doctag">@return</span></span>
<span class="hljs-comment">	 */</span>
	<span class="hljs-function"><span class="hljs-keyword">public</span> StudentNode <span class="hljs-title">getStuByRec</span><span class="hljs-params">(<span class="hljs-keyword">int</span> index)</span> </span>&#123;
		<span class="hljs-keyword">if</span>(head.next == <span class="hljs-keyword">null</span>) &#123;
			System.out.println(<span class="hljs-string">"链表为空!"</span>);
		&#125;
		StudentNode temp = head.next;
		<span class="hljs-comment">//用户记录链表长度，因为head.next不为空，此时已经有一个节点了</span>
		<span class="hljs-comment">//所以length初始化为1</span>
		<span class="hljs-keyword">int</span> length = <span class="hljs-number">1</span>;
		<span class="hljs-keyword">while</span>(temp.next != <span class="hljs-keyword">null</span>) &#123;
			temp = temp.next;
			length++;
		&#125;
		<span class="hljs-keyword">if</span>(length &lt; index) &#123;
			<span class="hljs-keyword">throw</span> <span class="hljs-keyword">new</span> RuntimeException(<span class="hljs-string">"链表越界"</span>);
		&#125;

		temp = head.next;
		<span class="hljs-keyword">for</span>(<span class="hljs-keyword">int</span> i = <span class="hljs-number">0</span>; i&lt;length-index; i++) &#123;
			temp = temp.next;
		&#125;
		<span class="hljs-keyword">return</span> temp;
	&#125;

	<span class="hljs-comment">/**</span>
<span class="hljs-comment">	 * 翻转链表</span>
<span class="hljs-comment">	 * <span class="hljs-doctag">@return</span> 反转后的链表</span>
<span class="hljs-comment">	 */</span>
	<span class="hljs-function"><span class="hljs-keyword">public</span> LinkedList <span class="hljs-title">reverseList</span><span class="hljs-params">()</span> </span>&#123;
		<span class="hljs-comment">//链表为空或者只有一个节点，无需翻转</span>
		<span class="hljs-keyword">if</span>(head.next == <span class="hljs-keyword">null</span> || head.next.next == <span class="hljs-keyword">null</span>) &#123;
			System.out.println(<span class="hljs-string">"无需翻转"</span>);
		&#125;
		LinkedList newLinkedList = <span class="hljs-keyword">new</span> LinkedList();
		<span class="hljs-comment">//给新链表创建新的头结点</span>
		newLinkedList.head = <span class="hljs-keyword">new</span> StudentNode(<span class="hljs-number">0</span>, <span class="hljs-string">""</span>);
		<span class="hljs-comment">//用于保存正在遍历的节点</span>
		StudentNode temp = head.next;
		<span class="hljs-comment">//用于保存正在遍历节点的下一个节点</span>
		StudentNode nextNode = temp.next;
		<span class="hljs-keyword">while</span>(<span class="hljs-keyword">true</span>) &#123;
			<span class="hljs-comment">//插入新链表</span>
			temp.next = newLinkedList.head.next;
			newLinkedList.head.next = temp;
			<span class="hljs-comment">//移动到下一个节点</span>
			temp = nextNode;
			nextNode = nextNode.next;
			<span class="hljs-keyword">if</span>(temp.next == <span class="hljs-keyword">null</span>) &#123;
				<span class="hljs-comment">//插入最后一个节点</span>
				temp.next = newLinkedList.head.next;
				newLinkedList.head.next = temp;
				head.next = <span class="hljs-keyword">null</span>;
				<span class="hljs-keyword">return</span> newLinkedList;
			&#125;
		&#125;
	&#125;

	<span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">reverseTraverse</span><span class="hljs-params">()</span> </span>&#123;
		<span class="hljs-keyword">if</span>(head == <span class="hljs-keyword">null</span>) &#123;
			System.out.println(<span class="hljs-string">"链表为空"</span>);
		&#125;

		StudentNode temp = head.next;
		<span class="hljs-comment">//创建栈，用于存放遍历到的节点</span>
		Stack&lt;StudentNode&gt; stack = <span class="hljs-keyword">new</span> Stack&lt;&gt;();
		<span class="hljs-keyword">while</span>(temp != <span class="hljs-keyword">null</span>) &#123;
			stack.push(temp);
			temp = temp.next;
		&#125;

		<span class="hljs-keyword">while</span> (!stack.isEmpty()) &#123;
			System.out.println(stack.pop());
		&#125;
	&#125;
&#125;

<span class="hljs-comment">/**</span>
<span class="hljs-comment"> * 定义节点</span>
<span class="hljs-comment"> */</span>
<span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">StudentNode</span> </span>&#123;
	<span class="hljs-keyword">int</span> id;
	String name;
	<span class="hljs-comment">//用于保存下一个节点的地址</span>
	StudentNode next;

	<span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-title">StudentNode</span><span class="hljs-params">(<span class="hljs-keyword">int</span> id, String name)</span> </span>&#123;
		<span class="hljs-keyword">this</span>.id = id;
		<span class="hljs-keyword">this</span>.name = name;
	&#125;

	<span class="hljs-meta">@Override</span>
	<span class="hljs-function"><span class="hljs-keyword">public</span> String <span class="hljs-title">toString</span><span class="hljs-params">()</span> </span>&#123;
		<span class="hljs-keyword">return</span> <span class="hljs-string">"StudentNode&#123;"</span> +
				<span class="hljs-string">"id="</span> + id +
				<span class="hljs-string">", name='"</span> + name + <span class="hljs-string">'\''</span> +
				<span class="hljs-string">'&#125;'</span>;
	&#125;
&#125;</code></pre>

<p>结果</p>
<pre><code class="hljs java">开始遍历链表
链表为空

开始遍历链表
StudentNode&#123;id=<span class="hljs-number">1</span>, name=<span class="hljs-string">'Nyima'</span>&#125;
StudentNode&#123;id=<span class="hljs-number">3</span>, name=<span class="hljs-string">'Lulu'</span>&#125;

有序插入
开始遍历链表
StudentNode&#123;id=<span class="hljs-number">0</span>, name=<span class="hljs-string">'Wenwen'</span>&#125;
StudentNode&#123;id=<span class="hljs-number">1</span>, name=<span class="hljs-string">'Nyima'</span>&#125;
StudentNode&#123;id=<span class="hljs-number">3</span>, name=<span class="hljs-string">'Lulu'</span>&#125;

修改学生信息
开始遍历链表
StudentNode&#123;id=<span class="hljs-number">0</span>, name=<span class="hljs-string">'Wenwen'</span>&#125;
StudentNode&#123;id=<span class="hljs-number">1</span>, name=<span class="hljs-string">'Hulu'</span>&#125;
StudentNode&#123;id=<span class="hljs-number">3</span>, name=<span class="hljs-string">'Lulu'</span>&#125;

删除学生信息
开始遍历链表
StudentNode&#123;id=<span class="hljs-number">0</span>, name=<span class="hljs-string">'Wenwen'</span>&#125;
StudentNode&#123;id=<span class="hljs-number">3</span>, name=<span class="hljs-string">'Lulu'</span>&#125;

获得倒数节点
StudentNode&#123;id=<span class="hljs-number">0</span>, name=<span class="hljs-string">'Wenwen'</span>&#125;

翻转链表
开始遍历链表
StudentNode&#123;id=<span class="hljs-number">3</span>, name=<span class="hljs-string">'Lulu'</span>&#125;
StudentNode&#123;id=<span class="hljs-number">0</span>, name=<span class="hljs-string">'Wenwen'</span>&#125;

倒序遍历链表
StudentNode&#123;id=<span class="hljs-number">0</span>, name=<span class="hljs-string">'Wenwen'</span>&#125;
StudentNode&#123;id=<span class="hljs-number">3</span>, name=<span class="hljs-string">'Lulu'</span>&#125;</code></pre>



<h2 id="2、双向链表"><a href="#2、双向链表" class="headerlink" title="2、双向链表"></a>2、双向链表</h2><h3 id="双向链表"><a href="#双向链表" class="headerlink" title="双向链表"></a>双向链表</h3><p><img src="https://nyimapicture.oss-cn-beijing.aliyuncs.com/img/20200616170404.png" srcset="/img/loading.gif" alt=""></p>
<h3 id="实现思路-1"><a href="#实现思路-1" class="headerlink" title="实现思路"></a>实现思路</h3><p><strong>遍历</strong></p>
<ul>
<li>和单向链表的遍历相同，需要一个辅助节点来保存当前正在遍历的节点</li>
</ul>
<p><strong>添加</strong></p>
<ul>
<li>双向链表多出了一个frnot，所以在添加时，要让新增节点的front指向链表尾节点</li>
</ul>
<p><strong>修改</strong></p>
<ul>
<li>和单向链表的修改相同</li>
</ul>
<p><strong>删除</strong></p>
<ul>
<li>使用temp来保存要删除的节点</li>
<li>temp.pre.next指向temp.next</li>
<li>temp.next指向temp.pre</li>
</ul>
<p><strong>代码</strong></p>
<pre><code class="hljs java"><span class="hljs-keyword">public</span> <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">Demo2</span> </span>&#123;
   <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">static</span> <span class="hljs-keyword">void</span> <span class="hljs-title">main</span><span class="hljs-params">(String[] args)</span> </span>&#123;
      BidirectionalList bidirectionalList = <span class="hljs-keyword">new</span> BidirectionalList();
      bidirectionalList.addNode(<span class="hljs-keyword">new</span> PersonNode(<span class="hljs-number">1</span>, <span class="hljs-string">"Nyima"</span>));
      bidirectionalList.addNode(<span class="hljs-keyword">new</span> PersonNode(<span class="hljs-number">2</span>, <span class="hljs-string">"Lulu"</span>));
      bidirectionalList.traverseNode();
      System.out.println();

      System.out.println(<span class="hljs-string">"修改节点信息"</span>);
      bidirectionalList.changeNode(<span class="hljs-keyword">new</span> PersonNode(<span class="hljs-number">2</span>, <span class="hljs-string">"Wenwen"</span>));
      bidirectionalList.traverseNode();
      System.out.println();

      <span class="hljs-comment">//删除节点</span>
      System.out.println(<span class="hljs-string">"删除节点"</span>);
      bidirectionalList.deleteNode(<span class="hljs-keyword">new</span> PersonNode(<span class="hljs-number">1</span>, <span class="hljs-string">"Nyima"</span>));
      bidirectionalList.traverseNode();
   &#125;
&#125;

<span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">BidirectionalList</span> </span>&#123;
   <span class="hljs-keyword">private</span> <span class="hljs-keyword">final</span> PersonNode head = <span class="hljs-keyword">new</span> PersonNode(-<span class="hljs-number">1</span>, <span class="hljs-string">""</span>);

   <span class="hljs-comment">/**</span>
<span class="hljs-comment">    * 判断双向链表是否为空</span>
<span class="hljs-comment">    * <span class="hljs-doctag">@return</span> 判空结果</span>
<span class="hljs-comment">    */</span>
   <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">boolean</span> <span class="hljs-title">isEmpty</span><span class="hljs-params">()</span> </span>&#123;
      <span class="hljs-keyword">return</span> head.next == <span class="hljs-keyword">null</span>;
   &#125;

   <span class="hljs-comment">/**</span>
<span class="hljs-comment">    * 添加将诶点</span>
<span class="hljs-comment">    * <span class="hljs-doctag">@param</span> node 要被添加的节点</span>
<span class="hljs-comment">    */</span>
   <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">addNode</span><span class="hljs-params">(PersonNode node)</span> </span>&#123;
      PersonNode temp = head;
      <span class="hljs-keyword">if</span>(temp.next != <span class="hljs-keyword">null</span>) &#123;
         temp = temp.next;
      &#125;
      <span class="hljs-comment">//插入在最后一个节点的后面</span>
      temp.next = node;
      node.front = temp;
   &#125;

    <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">traverseNode</span><span class="hljs-params">()</span> </span>&#123;
       System.out.println(<span class="hljs-string">"遍历链表"</span>);
      <span class="hljs-keyword">if</span> (isEmpty()) &#123;
         System.out.println(<span class="hljs-string">"链表为空"</span>);
         <span class="hljs-keyword">return</span>;
      &#125;
      PersonNode temp = head.next;
      <span class="hljs-keyword">while</span>(temp != <span class="hljs-keyword">null</span>) &#123;
         System.out.println(temp);
         temp = temp.next;
      &#125;
    &#125;

   <span class="hljs-comment">/**</span>
<span class="hljs-comment">    * 修改节点信息</span>
<span class="hljs-comment">    * <span class="hljs-doctag">@param</span> node 要修改的节点</span>
<span class="hljs-comment">    */</span>
    <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">changeNode</span><span class="hljs-params">(PersonNode node)</span> </span>&#123;
      <span class="hljs-keyword">if</span>(isEmpty()) &#123;
         System.out.println(<span class="hljs-string">"链表为空"</span>);
         <span class="hljs-keyword">return</span>;
      &#125;
      PersonNode temp = head.next;
      <span class="hljs-comment">//用于判定是否做了修改</span>
      <span class="hljs-keyword">boolean</span> flag = <span class="hljs-keyword">false</span>;
      <span class="hljs-keyword">while</span> (temp != <span class="hljs-keyword">null</span>) &#123;
         <span class="hljs-keyword">if</span>(temp.id == node.id) &#123;
            <span class="hljs-comment">//匹配到节点，替换节点</span>
            temp.front.next = node;
            node.next = temp.next;
            flag = <span class="hljs-keyword">true</span>;
         &#125;
         temp = temp.next;
      &#125;
      <span class="hljs-keyword">if</span>(!flag) &#123;
         System.out.println(<span class="hljs-string">"未匹配到改人信息"</span>);
      &#125;

    &#125;

   <span class="hljs-comment">/**</span>
<span class="hljs-comment">    * 删除节点</span>
<span class="hljs-comment">    * <span class="hljs-doctag">@param</span> node 要删除的节点</span>
<span class="hljs-comment">    */</span>
    <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">deleteNode</span><span class="hljs-params">(PersonNode node)</span> </span>&#123;
      <span class="hljs-keyword">if</span>(isEmpty())&#123;
         System.out.println(<span class="hljs-string">"链表为空"</span>);
         <span class="hljs-keyword">return</span>;
      &#125;
      PersonNode temp = head.next;
      <span class="hljs-comment">//查看是否删除成功</span>
       <span class="hljs-keyword">boolean</span> flag = <span class="hljs-keyword">false</span>;
      <span class="hljs-keyword">while</span>(temp != <span class="hljs-keyword">null</span>) &#123;
         <span class="hljs-keyword">if</span>(temp.id == node.id) &#123;
            temp.front.next = temp.next;
            temp.next = <span class="hljs-keyword">null</span>;
            flag = <span class="hljs-keyword">true</span>;
         &#125;
         temp = temp.next;
      &#125;
      <span class="hljs-keyword">if</span>(!flag) &#123;
         System.out.println(<span class="hljs-string">"未找到该节点"</span>);
      &#125;
    &#125;


&#125;

<span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">PersonNode</span> </span>&#123;
   <span class="hljs-keyword">int</span> id;
   String name;
   <span class="hljs-comment">//指向下一个节点</span>
   PersonNode next;
   <span class="hljs-comment">//指向前一个节点</span>
   PersonNode front;

   <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-title">PersonNode</span><span class="hljs-params">(<span class="hljs-keyword">int</span> id, String name)</span> </span>&#123;
      <span class="hljs-keyword">this</span>.id = id;
      <span class="hljs-keyword">this</span>.name = name;
   &#125;

   <span class="hljs-meta">@Override</span>
   <span class="hljs-function"><span class="hljs-keyword">public</span> String <span class="hljs-title">toString</span><span class="hljs-params">()</span> </span>&#123;
      <span class="hljs-keyword">return</span> <span class="hljs-string">"PersonNode&#123;"</span> +
            <span class="hljs-string">"id="</span> + id +
            <span class="hljs-string">", name='"</span> + name + <span class="hljs-string">'\''</span> +
            <span class="hljs-string">'&#125;'</span>;
   &#125;
&#125;</code></pre>

<p><strong>输出</strong></p>
<pre><code class="hljs routeros">遍历链表
PersonNode&#123;<span class="hljs-attribute">id</span>=1, <span class="hljs-attribute">name</span>=<span class="hljs-string">'Nyima'</span>&#125;
PersonNode&#123;<span class="hljs-attribute">id</span>=2, <span class="hljs-attribute">name</span>=<span class="hljs-string">'Lulu'</span>&#125;

修改节点信息
遍历链表
PersonNode&#123;<span class="hljs-attribute">id</span>=1, <span class="hljs-attribute">name</span>=<span class="hljs-string">'Nyima'</span>&#125;
PersonNode&#123;<span class="hljs-attribute">id</span>=2, <span class="hljs-attribute">name</span>=<span class="hljs-string">'Wenwen'</span>&#125;

删除节点
遍历链表
PersonNode&#123;<span class="hljs-attribute">id</span>=2, <span class="hljs-attribute">name</span>=<span class="hljs-string">'Wenwen'</span>&#125;</code></pre>



<h2 id="3、循环链表"><a href="#3、循环链表" class="headerlink" title="3、循环链表"></a>3、循环链表</h2><h3 id="循环链表"><a href="#循环链表" class="headerlink" title="循环链表"></a>循环链表</h3><p>单链表的尾节点指向首节点，即可构成循环链表</p>
<p><img src="https://nyimapicture.oss-cn-beijing.aliyuncs.com/img/20200616190405.png" srcset="/img/loading.gif" alt=""></p>
<h3 id="约瑟夫环"><a href="#约瑟夫环" class="headerlink" title="约瑟夫环"></a>约瑟夫环</h3><p>N个人围成一圈，从第S个开始报数，第M个将被杀掉，最后剩下一个，其余人都将被杀掉，求出被杀顺序</p>
<ul>
<li>例如N=6，M=5，S=1，被杀掉的顺序是：6，4，5，2，1，3</li>
</ul>
<p><strong>大致思路</strong></p>
<ul>
<li><p>遍历链表找到指定位置的节点</p>
</li>
<li><p>用一个front保存指定节点的前一个节点，方便删除</p>
</li>
<li><p>当count==time时，删除此时正在遍历的节点，放入数组中，<strong>并将count的值初始化</strong></p>
</li>
<li><p>用一个变量loopTime记录已经出圈了几个人，<strong>当其等于length时则是最后一个节点</strong>，直接放入数组并返回数即可</p>
</li>
</ul>
<p><strong>代码</strong></p>
<pre><code class="hljs java"><span class="hljs-keyword">public</span> <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">Demo3</span> </span>&#123;
	<span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">static</span> <span class="hljs-keyword">void</span> <span class="hljs-title">main</span><span class="hljs-params">(String[] args)</span> </span>&#123;
		CircularList circularList = <span class="hljs-keyword">new</span> CircularList();
		AttenderNode node1 = <span class="hljs-keyword">new</span> AttenderNode(<span class="hljs-number">1</span>);
		AttenderNode node2 = <span class="hljs-keyword">new</span> AttenderNode(<span class="hljs-number">2</span>);
		AttenderNode node3 = <span class="hljs-keyword">new</span> AttenderNode(<span class="hljs-number">3</span>);
		AttenderNode node4 = <span class="hljs-keyword">new</span> AttenderNode(<span class="hljs-number">4</span>);
		circularList.addNode(node1);
		circularList.addNode(node2);
		circularList.addNode(node3);
		circularList.addNode(node4);
		System.out.println(<span class="hljs-string">"约瑟夫环"</span>);
		AttenderNode[] arr = circularList.killAttender(<span class="hljs-number">1</span>, <span class="hljs-number">4</span>);
		<span class="hljs-keyword">for</span>(AttenderNode node : arr) &#123;
			System.out.println(node);
		&#125;


	&#125;
&#125;

<span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">CircularList</span> </span>&#123;
	<span class="hljs-keyword">private</span> <span class="hljs-keyword">final</span> AttenderNode head = <span class="hljs-keyword">new</span> AttenderNode(-<span class="hljs-number">1</span>);

	AttenderNode temp;

	<span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">addNode</span><span class="hljs-params">(AttenderNode node)</span> </span>&#123;
		<span class="hljs-keyword">if</span>(head.next == <span class="hljs-keyword">null</span>) &#123;
			head.next = node;
			<span class="hljs-keyword">return</span>;
		&#125;
		temp = head.next;
		<span class="hljs-comment">//只有一个节点，还没成环</span>
		<span class="hljs-keyword">if</span>(temp.next == <span class="hljs-keyword">null</span>) &#123;
			temp.next = node;
			node.next = head.next;
			<span class="hljs-keyword">return</span>;
		&#125;
		<span class="hljs-keyword">while</span> (temp.next != head.next) &#123;
			temp = temp.next;
		&#125;
		<span class="hljs-comment">//temp现在为尾节点</span>
		temp.next = node;
		<span class="hljs-comment">//node现在为尾节点，将其next指向首节点</span>
		node.next = head.next;
	&#125;

		<span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">int</span> <span class="hljs-title">getListLength</span><span class="hljs-params">()</span> </span>&#123;
			<span class="hljs-keyword">if</span>(head.next == <span class="hljs-keyword">null</span>) &#123;
				<span class="hljs-keyword">return</span> <span class="hljs-number">0</span>;
			&#125;
			<span class="hljs-comment">//判断是否只有一个节点</span>
			<span class="hljs-keyword">if</span>(head.next.next == <span class="hljs-keyword">null</span>) &#123;
				<span class="hljs-keyword">return</span> <span class="hljs-number">1</span>;
			&#125;
			<span class="hljs-comment">//节点个数初始为2</span>
			<span class="hljs-keyword">int</span> length = <span class="hljs-number">2</span>;
			AttenderNode first = head.next;
			AttenderNode temp = first.next;
			<span class="hljs-keyword">while</span>(<span class="hljs-keyword">true</span>) &#123;
				<span class="hljs-comment">//循环了一轮</span>
				<span class="hljs-keyword">if</span>(temp.next.id == first.id) &#123;
					<span class="hljs-keyword">return</span> length;
				&#125;
				temp = temp.next;
				length++;
			&#125;
		&#125;

	<span class="hljs-comment">/**</span>
<span class="hljs-comment">	 * 删除指定位置节点</span>
<span class="hljs-comment">	 * <span class="hljs-doctag">@param</span> time 次数</span>
<span class="hljs-comment">	 * <span class="hljs-doctag">@param</span> start 开始节点</span>
<span class="hljs-comment">	 * <span class="hljs-doctag">@return</span></span>
<span class="hljs-comment">	 */</span>
		<span class="hljs-keyword">public</span> AttenderNode[] killAttender(<span class="hljs-keyword">int</span> time, <span class="hljs-keyword">int</span> start) &#123;
			<span class="hljs-keyword">if</span>(head.next == <span class="hljs-keyword">null</span>) &#123;
				System.out.println(<span class="hljs-string">"链表为空"</span>);
				<span class="hljs-keyword">return</span> <span class="hljs-keyword">null</span>;
			&#125;
			temp = head.next;
			<span class="hljs-keyword">int</span> length = getListLength();
			<span class="hljs-comment">//存放退出队列的节点</span>
			AttenderNode[] arr = <span class="hljs-keyword">new</span> AttenderNode[length];
			<span class="hljs-comment">//从start开始计数</span>
			<span class="hljs-keyword">if</span>(start &gt; length) &#123;
				System.out.println(<span class="hljs-string">"超出链表范围"</span>);
				<span class="hljs-keyword">return</span> <span class="hljs-keyword">null</span>;
			&#125;
			AttenderNode startNode = temp;
			<span class="hljs-keyword">int</span> count;
			<span class="hljs-comment">//如果只有一个节点，直接返回</span>
			<span class="hljs-keyword">if</span>(temp.next == <span class="hljs-keyword">null</span>) &#123;
				arr[<span class="hljs-number">0</span>] = temp;
				<span class="hljs-keyword">return</span> arr;
			&#125;
			<span class="hljs-comment">//找到开始节点位置</span>
			<span class="hljs-keyword">for</span>(count = <span class="hljs-number">1</span>; count&lt;start; count++) &#123;
				startNode = startNode.next;
			&#125;
			<span class="hljs-comment">//找到start的前一个节点，方便删除操作</span>
			AttenderNode front = startNode.next;
			<span class="hljs-keyword">while</span>(front.next != startNode) &#123;
				front = front.next;
			&#125;
			<span class="hljs-comment">//开始选出节点出链表</span>
			temp = startNode;
			<span class="hljs-comment">//记录循环次数</span>
			<span class="hljs-keyword">int</span> loopTime = <span class="hljs-number">1</span>;
			<span class="hljs-keyword">int</span> index = <span class="hljs-number">0</span>;
			<span class="hljs-keyword">for</span>(count=<span class="hljs-number">1</span>; count&lt;=time; count++) &#123;
				<span class="hljs-keyword">if</span>(loopTime == length) &#123;
					<span class="hljs-comment">//放入最后一个节点</span>
					arr[index] = temp;
					<span class="hljs-keyword">return</span> arr;
				&#125;
				<span class="hljs-keyword">if</span>(count == time) &#123;
					arr[index] = temp;
					front.next = temp.next;
					index++;
					loopTime++;
					<span class="hljs-comment">//初始化，因为在循环开始时还会+1，所以这里初始化为0</span>
					count = <span class="hljs-number">0</span>;
				&#125;
				temp =front.next;
			&#125;
			<span class="hljs-keyword">return</span> arr;
		&#125;


&#125;

<span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">AttenderNode</span> </span>&#123;
	<span class="hljs-keyword">int</span> id;
	AttenderNode next;

	<span class="hljs-meta">@Override</span>
	<span class="hljs-function"><span class="hljs-keyword">public</span> String <span class="hljs-title">toString</span><span class="hljs-params">()</span> </span>&#123;
		<span class="hljs-keyword">return</span> <span class="hljs-string">"KillerNode&#123;"</span> +
				<span class="hljs-string">"id="</span> + id +
				<span class="hljs-string">'&#125;'</span>;
	&#125;

	<span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-title">AttenderNode</span><span class="hljs-params">(<span class="hljs-keyword">int</span> id)</span> </span>&#123;
		<span class="hljs-keyword">this</span>.id = id;
	&#125;
&#125;</code></pre>

<p><strong>运行结果</strong></p>
<pre><code class="hljs routeros">约瑟夫环
KillerNode&#123;<span class="hljs-attribute">id</span>=4&#125;
KillerNode&#123;<span class="hljs-attribute">id</span>=1&#125;
KillerNode&#123;<span class="hljs-attribute">id</span>=2&#125;
KillerNode&#123;<span class="hljs-attribute">id</span>=3&#125;</code></pre>



<h2 id="4、跳跃表"><a href="#4、跳跃表" class="headerlink" title="4、跳跃表"></a>4、跳跃表</h2><p>详见<a href="https://nyimac.gitee.io/2020/11/08/Redis%E8%AE%BE%E8%AE%A1%E4%B8%8E%E5%AE%9E%E7%8E%B0/#1%E3%80%81%E4%BB%80%E4%B9%88%E6%98%AF%E8%B7%B3%E8%B7%83%E8%A1%A8"><strong>Redis设计与实现——跳跃表</strong></a></p>
<h1 id="三、栈"><a href="#三、栈" class="headerlink" title="三、栈"></a>三、栈</h1><h2 id="1、定义"><a href="#1、定义" class="headerlink" title="1、定义"></a>1、定义</h2><ul>
<li>栈是一个<strong>先入后出</strong>的有序列表</li>
<li>栈(stack)是限制线性表中元素的插入和删除只能在线性表的<strong>同一端进行</strong>的一种特殊线性表。允许插入和删除的一端，为变化的一端，称为栈顶，另一端为固定的一端，称为栈底</li>
<li>最先放入的元素在栈底，且最后出栈。最后放入的元素在栈顶，且最先出栈</li>
</ul>
<p><img src="https://nyimapicture.oss-cn-beijing.aliyuncs.com/img/20200617090532.png" srcset="/img/loading.gif" alt=""></p>
<h2 id="2、应用场景"><a href="#2、应用场景" class="headerlink" title="2、应用场景"></a>2、应用场景</h2><ul>
<li>子程序递归调用。如JVM中的虚拟机栈</li>
<li>表达式转换（中缀转后缀）与求值</li>
<li>二叉树的遍历</li>
<li>图的深度优先遍历</li>
</ul>
<h2 id="3、实现"><a href="#3、实现" class="headerlink" title="3、实现"></a>3、实现</h2><h3 id="用数组实现"><a href="#用数组实现" class="headerlink" title="用数组实现"></a>用数组实现</h3><p><strong>思路</strong></p>
<ul>
<li>定义top表示栈顶，初始值为-1</li>
<li>入栈的操作，先让top++，再放入数组</li>
<li>出栈操作，先取出元素，在让top–</li>
<li>top == -1时，栈空</li>
<li>top == maxSize-1时，栈满</li>
</ul>
<p><strong>代码</strong></p>
<pre><code class="hljs java"><span class="hljs-keyword">public</span> <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">Demo1</span> </span>&#123;
   <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">static</span> <span class="hljs-keyword">void</span> <span class="hljs-title">main</span><span class="hljs-params">(String[] args)</span> </span>&#123;
      ArrayStack stack = <span class="hljs-keyword">new</span> ArrayStack(<span class="hljs-number">5</span>);
      <span class="hljs-comment">//压栈</span>
      stack.push(<span class="hljs-number">1</span>);
      stack.push(<span class="hljs-number">2</span>);
      stack.push(<span class="hljs-number">3</span>);
      stack.push(<span class="hljs-number">4</span>);
      stack.push(<span class="hljs-number">5</span>);
      <span class="hljs-comment">//出栈</span>
      System.out.println(stack.pop());
   &#125;
&#125;

<span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">ArrayStack</span> </span>&#123;
   <span class="hljs-keyword">private</span> <span class="hljs-keyword">final</span> <span class="hljs-keyword">int</span> maxSize;
   <span class="hljs-keyword">int</span>[] stack;
   <span class="hljs-keyword">private</span> <span class="hljs-keyword">int</span> top;

   <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-title">ArrayStack</span><span class="hljs-params">(<span class="hljs-keyword">int</span> maxSize)</span> </span>&#123;
      <span class="hljs-keyword">this</span>.maxSize = maxSize;
      stack = <span class="hljs-keyword">new</span> <span class="hljs-keyword">int</span> [<span class="hljs-keyword">this</span>.maxSize];
      top = -<span class="hljs-number">1</span>;
   &#125;

   <span class="hljs-function"><span class="hljs-keyword">private</span> <span class="hljs-keyword">boolean</span> <span class="hljs-title">isEmpty</span><span class="hljs-params">()</span> </span>&#123;
      <span class="hljs-keyword">return</span> top == -<span class="hljs-number">1</span>;
   &#125;

   <span class="hljs-function"><span class="hljs-keyword">private</span> <span class="hljs-keyword">boolean</span> <span class="hljs-title">isFull</span><span class="hljs-params">()</span> </span>&#123;
      <span class="hljs-keyword">return</span> top == maxSize-<span class="hljs-number">1</span>;
   &#125;

   <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">push</span><span class="hljs-params">(<span class="hljs-keyword">int</span> i)</span> </span>&#123;
      <span class="hljs-keyword">if</span>(isFull()) &#123;
         <span class="hljs-keyword">throw</span> <span class="hljs-keyword">new</span> StackOverflowError(<span class="hljs-string">"栈满"</span>);
      &#125;
      <span class="hljs-comment">//压栈</span>
      top++;
      stack[top] = i;
   &#125;

   <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">int</span> <span class="hljs-title">pop</span><span class="hljs-params">()</span> </span>&#123;
      <span class="hljs-keyword">if</span>(isEmpty()) &#123;
         <span class="hljs-keyword">throw</span> <span class="hljs-keyword">new</span> EmptyStackException();
      &#125;
      <span class="hljs-keyword">int</span> retNum = stack[top];
      top--;
      <span class="hljs-keyword">return</span> retNum;
   &#125;
&#125;</code></pre>



<h2 id="4、应用"><a href="#4、应用" class="headerlink" title="4、应用"></a>4、应用</h2><h3 id="表达式求值"><a href="#表达式求值" class="headerlink" title="表达式求值"></a>表达式求值</h3><p><strong>思路</strong></p>
<p><img src="https://nyimapicture.oss-cn-beijing.aliyuncs.com/img/20200617103635.png" srcset="/img/loading.gif" alt=""></p>
<ul>
<li>准备一个索引index来帮助我们遍历表达式</li>
<li>如果index位置上的元素是一个数字，就直接入栈</li>
<li>如果index位置上的元素是一个符号<ul>
<li>如果符号栈为空，直接入栈</li>
<li>如果符号栈不为空<ul>
<li>index位置上的符号的优先级小于或等于栈顶符号的优先级，则弹出两个数栈中的元素和符号栈中的一个符号，并且进行计算。将运算结果放入数栈中，并将index位置上的符号压入符号栈</li>
<li>index位置上的符号的优先级大于符号栈栈顶符号的优先级，则将该符号压入符号栈</li>
</ul>
</li>
</ul>
</li>
<li>当表达式遍历完毕后，就弹出数栈中的2个数字和符号栈中的1个符号进行运算，并将运行结果入栈</li>
<li>最终数栈中只有一个值，这个值便是运算结果</li>
<li>注意：<ul>
<li>读取的是字符，所以存入数字前需要减去0的ASCII码</li>
<li>如果数字是多位数，需要一直读，读到下一位不是数字为止，然后将读到的字符进行拼接，然后一起压入数栈</li>
</ul>
</li>
</ul>
<p><strong>代码</strong></p>
<p>存在的问题：因为栈是用的整型数组，所以计算除法的时候，无法转化成double</p>
<pre><code class="hljs java"><span class="hljs-keyword">public</span> <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">Demo2</span> </span>&#123;
	<span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">static</span> <span class="hljs-keyword">void</span> <span class="hljs-title">main</span><span class="hljs-params">(String[] args)</span> </span>&#123;
		String formula = <span class="hljs-string">"12+3*15+3/3"</span>;
		<span class="hljs-comment">//索引，用来读取字符串中的元素</span>
		<span class="hljs-keyword">int</span> index = <span class="hljs-number">0</span>;
		<span class="hljs-comment">//保存读取到的数字和符号</span>
		<span class="hljs-keyword">int</span> number1 = <span class="hljs-number">0</span>;
		<span class="hljs-keyword">int</span> number2 = <span class="hljs-number">0</span>;
		<span class="hljs-keyword">int</span> thisChar = <span class="hljs-string">' '</span>;
		<span class="hljs-comment">//用于拼接数字</span>
		StringBuilder spliceNumber = <span class="hljs-keyword">new</span> StringBuilder();
		<span class="hljs-comment">//数栈和符号栈</span>
		ArrayStack2 numberStack = <span class="hljs-keyword">new</span> ArrayStack2(<span class="hljs-number">10</span>);
		ArrayStack2 operationStack = <span class="hljs-keyword">new</span> ArrayStack2(<span class="hljs-number">10</span>);
		<span class="hljs-comment">//保存运算结果</span>
		<span class="hljs-keyword">int</span> result;

		<span class="hljs-comment">//开始读取字符串中的元素</span>
		<span class="hljs-keyword">for</span> (index = <span class="hljs-number">0</span>; index &lt; formula.length(); index++) &#123;
			thisChar = formula.charAt(index);
			<span class="hljs-keyword">if</span> (operationStack.isOperation(thisChar)) &#123;
				<span class="hljs-keyword">if</span>(operationStack.comparePriority(thisChar)) &#123;
					operationStack.push(thisChar);
				&#125; <span class="hljs-keyword">else</span> &#123;
					<span class="hljs-keyword">int</span> popChar = operationStack.pop();
					number2 = numberStack.pop();
					number1 = numberStack.pop();
					<span class="hljs-comment">//获得运算结果</span>
					result = operationStack.calculation(number1, number2, popChar);
					operationStack.push(thisChar);
					numberStack.push(result);
				&#125;
			&#125; <span class="hljs-keyword">else</span> &#123;
				<span class="hljs-comment">//如果是数字，就一直读取</span>
				<span class="hljs-keyword">while</span>(thisChar&gt;=<span class="hljs-string">'0'</span> &amp;&amp; thisChar&lt;=<span class="hljs-string">'9'</span>) &#123;
					<span class="hljs-comment">//可能该数字为多位数，所以不能只存入一位数字</span>
					spliceNumber.append(thisChar - <span class="hljs-string">'0'</span>);
					System.out.println(<span class="hljs-string">"拼接字符换 "</span> + spliceNumber);
					index++;
					<span class="hljs-comment">//如果已经读了最后一个数字了，就停下来</span>
					<span class="hljs-keyword">if</span>(index &gt;= formula.length()) &#123;
						<span class="hljs-keyword">break</span>;
					&#125;
					thisChar = formula.charAt(index);
				&#125;
				<span class="hljs-keyword">int</span> number = Integer.parseInt(spliceNumber.toString());
				numberStack.push(number);
				<span class="hljs-comment">//初始化spliceNumber</span>
				spliceNumber = <span class="hljs-keyword">new</span> StringBuilder();
				index--;
			&#125;
		&#125;

		<span class="hljs-keyword">while</span>(!operationStack.isEmpty()) &#123;
			<span class="hljs-keyword">int</span> popChar = operationStack.pop();
			number2 = numberStack.pop();
			number1 = numberStack.pop();
			<span class="hljs-comment">//获得运算结果</span>
			result = operationStack.calculation(number1, number2, popChar);
			numberStack.push(result);
		&#125;

		System.out.println(numberStack.pop());
	&#125;
&#125;

<span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">ArrayStack2</span> </span>&#123;
	<span class="hljs-keyword">private</span> <span class="hljs-keyword">final</span> <span class="hljs-keyword">int</span> maxSize;
	<span class="hljs-keyword">int</span>[] stack;
	<span class="hljs-keyword">private</span> <span class="hljs-keyword">int</span> top;

	<span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-title">ArrayStack2</span><span class="hljs-params">(<span class="hljs-keyword">int</span> maxSize)</span> </span>&#123;
		<span class="hljs-keyword">this</span>.maxSize = maxSize;
		stack = <span class="hljs-keyword">new</span> <span class="hljs-keyword">int</span>[<span class="hljs-keyword">this</span>.maxSize];
		top = -<span class="hljs-number">1</span>;
	&#125;

	<span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">boolean</span> <span class="hljs-title">isEmpty</span><span class="hljs-params">()</span> </span>&#123;
		<span class="hljs-keyword">return</span> top == -<span class="hljs-number">1</span>;
	&#125;

	 <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">boolean</span> <span class="hljs-title">isFull</span><span class="hljs-params">()</span> </span>&#123;
		<span class="hljs-keyword">return</span> top == maxSize - <span class="hljs-number">1</span>;
	&#125;

	<span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">push</span><span class="hljs-params">(<span class="hljs-keyword">int</span> i)</span> </span>&#123;
		<span class="hljs-keyword">if</span> (isFull()) &#123;
			<span class="hljs-keyword">throw</span> <span class="hljs-keyword">new</span> StackOverflowError(<span class="hljs-string">"栈满"</span>);
		&#125;
		<span class="hljs-comment">//压栈</span>
		top++;
		stack[top] = i;
	&#125;

	<span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">int</span> <span class="hljs-title">pop</span><span class="hljs-params">()</span> </span>&#123;
		<span class="hljs-keyword">if</span> (isEmpty()) &#123;
			<span class="hljs-keyword">throw</span> <span class="hljs-keyword">new</span> EmptyStackException();
		&#125;
		<span class="hljs-keyword">int</span> retNum = stack[top];
		top--;
		<span class="hljs-keyword">return</span> retNum;
	&#125;

	<span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span>  <span class="hljs-title">traverse</span><span class="hljs-params">()</span> </span>&#123;
		<span class="hljs-keyword">for</span>(<span class="hljs-keyword">int</span> thiChar : stack) &#123;
			System.out.println(thiChar);
		&#125;
	&#125;

	<span class="hljs-comment">/**</span>
<span class="hljs-comment">	 * 判断符号的优先级</span>
<span class="hljs-comment">	 *</span>
<span class="hljs-comment">	 * <span class="hljs-doctag">@param</span> operation 传入运算符</span>
<span class="hljs-comment">	 * <span class="hljs-doctag">@return</span> 返回优先级</span>
<span class="hljs-comment">	 */</span>
	<span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">int</span> <span class="hljs-title">getPriority</span><span class="hljs-params">(<span class="hljs-keyword">int</span> operation)</span> </span>&#123;
		<span class="hljs-keyword">if</span> (operation == <span class="hljs-string">'*'</span> || operation == <span class="hljs-string">'/'</span>) &#123;
			<span class="hljs-keyword">return</span> <span class="hljs-number">2</span>;
		&#125; <span class="hljs-keyword">else</span> <span class="hljs-keyword">if</span> (operation == <span class="hljs-string">'+'</span> || operation == <span class="hljs-string">'-'</span>) &#123;
			<span class="hljs-keyword">return</span> <span class="hljs-number">1</span>;
		&#125; <span class="hljs-keyword">else</span> <span class="hljs-keyword">if</span> (operation &gt;= <span class="hljs-string">'0'</span> &amp;&amp; operation &lt;= <span class="hljs-string">'9'</span>) &#123;
			<span class="hljs-keyword">return</span> <span class="hljs-number">0</span>;
		&#125; <span class="hljs-keyword">else</span> &#123;
			<span class="hljs-keyword">return</span> -<span class="hljs-number">1</span>;
		&#125;
	&#125;

	<span class="hljs-comment">/**</span>
<span class="hljs-comment">	 * 比较栈顶元素和传入字符的优先级大小</span>
<span class="hljs-comment">	 *</span>
<span class="hljs-comment">	 * <span class="hljs-doctag">@param</span> operation 传入字符</span>
<span class="hljs-comment">	 * <span class="hljs-doctag">@return</span> true则是传入字符优先级大于栈顶字符，false反之</span>
<span class="hljs-comment">	 */</span>
	<span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">boolean</span> <span class="hljs-title">comparePriority</span><span class="hljs-params">(<span class="hljs-keyword">int</span> operation)</span> </span>&#123;
		<span class="hljs-keyword">if</span> (isEmpty()) &#123;
			<span class="hljs-keyword">return</span> <span class="hljs-keyword">true</span>;
		&#125; <span class="hljs-keyword">else</span> &#123;
  			<span class="hljs-keyword">int</span> priority1 = getPriority(operation);
  			<span class="hljs-keyword">int</span> priority2 = getPriority(stack[top]);
			<span class="hljs-keyword">return</span> priority1 &gt; priority2;
		&#125;
	&#125;

	<span class="hljs-comment">/**</span>
<span class="hljs-comment">	 * 判断该位置是不是一个符号</span>
<span class="hljs-comment">	 *</span>
<span class="hljs-comment">	 * <span class="hljs-doctag">@param</span> operation 该位置的符号</span>
<span class="hljs-comment">	 * <span class="hljs-doctag">@return</span> 判断结果</span>
<span class="hljs-comment">	 */</span>
	<span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">boolean</span> <span class="hljs-title">isOperation</span><span class="hljs-params">(<span class="hljs-keyword">int</span> operation)</span> </span>&#123;
		<span class="hljs-keyword">return</span> operation == <span class="hljs-string">'*'</span> || operation == <span class="hljs-string">'/'</span> || operation == <span class="hljs-string">'-'</span> || operation == <span class="hljs-string">'+'</span>;
	&#125;

	<span class="hljs-comment">/**</span>
<span class="hljs-comment">	 * <span class="hljs-doctag">@param</span> number1   第一个运算的数字</span>
<span class="hljs-comment">	 * <span class="hljs-doctag">@param</span> number2   第二个运算的数字</span>
<span class="hljs-comment">	 * <span class="hljs-doctag">@param</span> operation 运算符</span>
<span class="hljs-comment">	 * <span class="hljs-doctag">@return</span></span>
<span class="hljs-comment">	 */</span>
	<span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">int</span> <span class="hljs-title">calculation</span><span class="hljs-params">(<span class="hljs-keyword">int</span> number1, <span class="hljs-keyword">int</span> number2, <span class="hljs-keyword">int</span> operation)</span> </span>&#123;
		<span class="hljs-keyword">switch</span> (operation) &#123;
			<span class="hljs-keyword">case</span> <span class="hljs-string">'+'</span>:
				<span class="hljs-keyword">return</span> number1+number2;
			<span class="hljs-keyword">case</span> <span class="hljs-string">'-'</span>:
				<span class="hljs-keyword">return</span> number1-number2;
			<span class="hljs-keyword">case</span> <span class="hljs-string">'*'</span>:
				<span class="hljs-keyword">return</span> number1*number2;
			<span class="hljs-keyword">case</span> <span class="hljs-string">'/'</span>:
				<span class="hljs-keyword">return</span> number1/number2;
			<span class="hljs-keyword">default</span>:
				System.out.println(operation);
				<span class="hljs-keyword">throw</span> <span class="hljs-keyword">new</span> RuntimeException(<span class="hljs-string">"符号读取错误！"</span>);
		&#125;
	&#125;
&#125;</code></pre>

<p>结果</p>
<pre><code class="hljs angelscript"><span class="hljs-number">58</span></code></pre>



<h2 id="5、中缀转后缀"><a href="#5、中缀转后缀" class="headerlink" title="5、中缀转后缀"></a>5、中缀转后缀</h2><p><strong>后缀表达式</strong>运算方法</p>
<ul>
<li><p>从左向右读取表达式</p>
<ul>
<li>遇到数字就压入栈中</li>
<li>遇到运算符就弹出栈顶和次顶元素。用<strong>次顶元素 运算符 栈顶元素</strong>，并将运算结果压入栈中，直到栈为空，最终结果就是运算结果</li>
</ul>
</li>
</ul>
<h3 id="设计"><a href="#设计" class="headerlink" title="设计"></a><strong>设计</strong></h3><p><strong>中缀表达式转后缀表达式</strong></p>
<ul>
<li><strong>从左向右</strong>读取中缀表达式，并且创建<strong>栈s</strong>和<strong>队列q</strong></li>
<li>如果读到的元素的数字，就直接入队放入q中</li>
<li>如果读到的是<strong>运算符</strong>（运算符判定）<ul>
<li>如果s为空，则将该运算符压入s</li>
<li>如果s不为空<ul>
<li>如果该运算符为<strong>左括号</strong>，则直接压入s</li>
<li>如果该运算符为<strong>右括号</strong>，则将s中的元素依次出栈并入队到q中，<strong>直到遇见左括号为止</strong>（括号不放入q中）</li>
<li>如果该运算符的优先级<strong>高于</strong>s栈顶的运算符，则将该元素压入s</li>
<li>如果该运算符的优先级<strong>小于等于</strong>s栈顶的运算符，则弹出s栈顶的元素，并将其放入q中，该运算符重<strong>新判定</strong>入栈操作（运算符判定步骤）</li>
</ul>
</li>
</ul>
</li>
<li>如果中缀表达式已经读取完毕，则将s中的元素依次出栈，放入q中</li>
<li>q中的元素依次出队，该顺序即为后缀表达式</li>
</ul>
<p><strong>代码</strong></p>
<pre><code class="hljs java"><span class="hljs-comment">/**</span>
<span class="hljs-comment"> * <span class="hljs-doctag">@author</span> Chen Panwen</span>
<span class="hljs-comment"> * <span class="hljs-doctag">@data</span> 2020/6/17 21:07</span>
<span class="hljs-comment"> */</span>
<span class="hljs-keyword">public</span> <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">Demo4</span> </span>&#123;
   <span class="hljs-keyword">static</span> Queue&lt;String&gt; queue = <span class="hljs-keyword">new</span> LinkedList&lt;&gt;();
   <span class="hljs-keyword">static</span> Stack&lt;String&gt; stack = <span class="hljs-keyword">new</span> Stack&lt;&gt;();

   <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">static</span> <span class="hljs-keyword">void</span> <span class="hljs-title">main</span><span class="hljs-params">(String[] args)</span> </span>&#123;
      <span class="hljs-comment">//中缀表达式，加上空格，方便取出</span>
      String infixExpression = <span class="hljs-string">"1 + ( ( 2 + 3 ) * 4 ) - 5"</span>;
      String[] expressionArr = infixExpression.split(<span class="hljs-string">" "</span>);
      <span class="hljs-comment">//用来保存该运算符的类型</span>
      <span class="hljs-keyword">int</span> type;
      <span class="hljs-comment">//取出的字符串</span>
      String element;
      <span class="hljs-comment">//弹出栈的字符串</span>
      String stackEle;
      <span class="hljs-keyword">for</span>(<span class="hljs-keyword">int</span> i=<span class="hljs-number">0</span>; i&lt;expressionArr.length; i++) &#123;
         element = expressionArr[i];
         type = judgeOperator(element);
         <span class="hljs-keyword">if</span>(type == <span class="hljs-number">0</span>) &#123;
            <span class="hljs-comment">//数字，直接入队</span>
            queue.add(element);
         &#125;<span class="hljs-keyword">else</span> <span class="hljs-keyword">if</span>(type == <span class="hljs-number">1</span>) &#123;
            <span class="hljs-comment">//左括号，直接压栈</span>
            stack.push(element);
         &#125;<span class="hljs-keyword">else</span> <span class="hljs-keyword">if</span>(type == <span class="hljs-number">3</span>) &#123;
            <span class="hljs-comment">//如果右括号，弹出栈顶元素，直到遇见左括号位置再停下来</span>
            <span class="hljs-keyword">do</span> &#123;
               stackEle = stack.pop();
               <span class="hljs-keyword">if</span>(stackEle.equals(<span class="hljs-string">"("</span>)) &#123;
                  <span class="hljs-keyword">break</span>;
               &#125;
               queue.add(stackEle);
               <span class="hljs-comment">//弹出栈中的左括号</span>
            &#125;<span class="hljs-keyword">while</span> (!stackEle.equals(<span class="hljs-string">"("</span>));
         &#125;<span class="hljs-keyword">else</span> <span class="hljs-keyword">if</span>(type == <span class="hljs-number">2</span>) &#123;
            <span class="hljs-keyword">if</span>(stack.isEmpty()) &#123;
               <span class="hljs-comment">//如果栈为空，直接入栈</span>
               stack.push(element);
               <span class="hljs-keyword">continue</span>;
            &#125;
            <span class="hljs-keyword">int</span> priority1 = getPriority(element);
            <span class="hljs-comment">//获得栈顶元素，并判断其优先级</span>
            stackEle = stack.peek();
            <span class="hljs-keyword">int</span> priority2 = getPriority(stackEle);
            <span class="hljs-keyword">if</span>(priority2 == <span class="hljs-number">0</span>) &#123;
               <span class="hljs-comment">//为左括号，运算符直接入栈</span>
               stack.push(element);
            &#125;<span class="hljs-keyword">else</span> <span class="hljs-keyword">if</span>(priority1 &gt; priority2) &#123;
               <span class="hljs-comment">//该运算符优先级高于栈顶元素优先级，则入栈</span>
               stack.push(element);
            &#125;<span class="hljs-keyword">else</span> &#123;
               stackEle = stack.pop();
               queue.add(stackEle);
               <span class="hljs-comment">//重新判断该运算符</span>
               i--;
            &#125;
         &#125;
      &#125;
      <span class="hljs-comment">//把最后一个元素出栈并入队</span>
      stackEle = stack.pop();
      queue.add(stackEle);
      <span class="hljs-comment">//保存队列长度，因为出队过程中队列的长度会被改变</span>
      <span class="hljs-keyword">int</span> length = queue.size();
      <span class="hljs-keyword">for</span>(<span class="hljs-keyword">int</span> i=<span class="hljs-number">0</span>; i&lt;length; i++) &#123;
         element = queue.remove();
         System.out.print(element);
      &#125;
   &#125;

   <span class="hljs-comment">/**</span>
<span class="hljs-comment">    * 判断该运算符是不是加减乘除</span>
<span class="hljs-comment">    * <span class="hljs-doctag">@param</span> operation 运算符</span>
<span class="hljs-comment">    * <span class="hljs-doctag">@return</span> true则该运算符为加减乘除</span>
<span class="hljs-comment">    */</span>
   <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">static</span> <span class="hljs-keyword">boolean</span> <span class="hljs-title">firstJudge</span><span class="hljs-params">(String operation)</span> </span>&#123;
      <span class="hljs-keyword">return</span> operation.equals(<span class="hljs-string">"*"</span>) || operation.equals(<span class="hljs-string">"/"</span>) || operation.equals(<span class="hljs-string">"+"</span>) || operation.equals(<span class="hljs-string">"-"</span>);
   &#125;


   <span class="hljs-comment">/**</span>
<span class="hljs-comment">    * 判断该字符串的类型</span>
<span class="hljs-comment">    * <span class="hljs-doctag">@param</span> operation 要判断的字符串</span>
<span class="hljs-comment">    * <span class="hljs-doctag">@return</span> 3-&gt;右括号 2-&gt;加减乘除运算符 1-&gt;左括号</span>
<span class="hljs-comment">    */</span>
   <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">static</span> <span class="hljs-keyword">int</span> <span class="hljs-title">judgeOperator</span><span class="hljs-params">(String operation)</span> </span>&#123;
      <span class="hljs-keyword">if</span>(operation.equals(<span class="hljs-string">")"</span>)) &#123;
         <span class="hljs-keyword">return</span> <span class="hljs-number">3</span>;
      &#125;
      <span class="hljs-keyword">if</span>(firstJudge(operation)) &#123;
         <span class="hljs-keyword">return</span> <span class="hljs-number">2</span>;
      &#125;
      <span class="hljs-keyword">if</span>(operation.equals(<span class="hljs-string">"("</span>)) &#123;
         <span class="hljs-keyword">return</span> <span class="hljs-number">1</span>;
      &#125; <span class="hljs-keyword">else</span> &#123;
         <span class="hljs-keyword">return</span> <span class="hljs-number">0</span>;
      &#125;
   &#125;

   <span class="hljs-comment">/**</span>
<span class="hljs-comment">    * 判断运算符优先级</span>
<span class="hljs-comment">    * <span class="hljs-doctag">@param</span> operator 要判断的运算符</span>
<span class="hljs-comment">    * <span class="hljs-doctag">@return</span> 2代表乘除，1代表加减，0代表左括号</span>
<span class="hljs-comment">    */</span>
   <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">static</span> <span class="hljs-keyword">int</span> <span class="hljs-title">getPriority</span><span class="hljs-params">(String operator)</span> </span>&#123;
      <span class="hljs-keyword">if</span>(operator.equals(<span class="hljs-string">"*"</span>) || operator.equals(<span class="hljs-string">"/"</span>)) &#123;
         <span class="hljs-keyword">return</span> <span class="hljs-number">2</span>;
      &#125;<span class="hljs-keyword">else</span> <span class="hljs-keyword">if</span>(operator.equals(<span class="hljs-string">"+"</span>) || operator.equals(<span class="hljs-string">"-"</span>)) &#123;
         <span class="hljs-keyword">return</span> <span class="hljs-number">1</span>;
      &#125; <span class="hljs-keyword">else</span> &#123;
         <span class="hljs-keyword">return</span> <span class="hljs-number">0</span>;
      &#125;

   &#125;
&#125;</code></pre>

<p>结果</p>
<pre><code class="hljs angelscript"><span class="hljs-number">123</span>+<span class="hljs-number">4</span>*+<span class="hljs-number">5</span>-</code></pre>



<h1 id="四、递归"><a href="#四、递归" class="headerlink" title="四、递归"></a>四、递归</h1><h2 id="1、概念"><a href="#1、概念" class="headerlink" title="1、概念"></a>1、概念</h2><p> <strong>递归就是方法自己调用自己</strong>,每次调用时<strong>传入不同的变量</strong>.递归有助于编程者解决复杂的问题,同时可以让代码变得简洁。并且递归用到了<strong>虚拟机栈</strong></p>
<p><img src="https://nyimapicture.oss-cn-beijing.aliyuncs.com/img/20200618210040.png" srcset="/img/loading.gif" alt=""></p>
<h2 id="2、能解决的问题"><a href="#2、能解决的问题" class="headerlink" title="2、能解决的问题"></a>2、能解决的问题</h2><p><strong>数学问题</strong></p>
<ul>
<li>八皇后问题</li>
<li>汉诺塔</li>
<li>求阶乘</li>
<li>迷宫问题</li>
<li>球和篮子</li>
</ul>
<p><strong>各种排序算法</strong></p>
<h2 id="3、规则"><a href="#3、规则" class="headerlink" title="3、规则"></a>3、规则</h2><ul>
<li><p>方法的变量是独立的，不会相互影响的</p>
</li>
<li><p>如果方法中使用的是引用类型变量(比如数组)，就会共享该引用类型的数据</p>
</li>
<li><p>递归<strong>必须向退出递归的条件逼近</strong>，否则就是无限递归，出现 StackOverflowError</p>
</li>
<li><p>当一个方法执行完毕，或者遇到 return，就会返回，<strong>遵守谁调用，就将结果返回给谁</strong>，同时当方法执行完毕或</p>
<p> 者返回时，该方法也就执行完毕</p>
</li>
</ul>
<h2 id="4、迷宫问题"><a href="#4、迷宫问题" class="headerlink" title="4、迷宫问题"></a>4、迷宫问题</h2><p><strong>思路</strong></p>
<ul>
<li>用一个二维矩阵代表地图<ul>
<li>1代表边界</li>
<li>0代表未做过该地点</li>
<li>2代表走过且能走得通</li>
<li>3代表走过但走不通</li>
</ul>
</li>
<li>设置起点和终点以及每个地点的<strong>行走策略</strong><ul>
<li>行走策略指<strong>在该点所走的方向的顺序</strong>，如 右-&gt;下-&gt;左-&gt;上（调用寻找路径的方法，使用递归）</li>
</ul>
</li>
<li>每次行走时假设该点能够走通，然后按照策略去判断，如果所有策略判断后都走不通，则<strong>该点走不通</strong></li>
</ul>
<p><strong>图解</strong></p>
<p>初始地图</p>
<p><img src="https://nyimapicture.oss-cn-beijing.aliyuncs.com/img/20200618223850.png" srcset="/img/loading.gif" alt=""></p>
<p><strong>行走路径</strong></p>
<p>策略：右下左上</p>
<p><img src="https://nyimapicture.oss-cn-beijing.aliyuncs.com/img/20200618224021.png" srcset="/img/loading.gif" alt=""></p>
<p><strong>代码</strong></p>
<pre><code class="hljs java"><span class="hljs-keyword">public</span> <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">Demo2</span> </span>&#123;
   <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">static</span> <span class="hljs-keyword">void</span> <span class="hljs-title">main</span><span class="hljs-params">(String[] args)</span> </span>&#123;
      <span class="hljs-comment">//得到地图</span>
      <span class="hljs-keyword">int</span> length = <span class="hljs-number">7</span>;
      <span class="hljs-keyword">int</span> width = <span class="hljs-number">6</span>;
      <span class="hljs-keyword">int</span>[][] map = getMap(length, width);

      <span class="hljs-comment">//设置一些障碍</span>
      map[<span class="hljs-number">1</span>][<span class="hljs-number">2</span>] = <span class="hljs-number">1</span>;
      map[<span class="hljs-number">2</span>][<span class="hljs-number">2</span>] = <span class="hljs-number">1</span>;

      <span class="hljs-comment">//打印地图</span>
      System.out.println(<span class="hljs-string">"地图如下"</span>);
      <span class="hljs-keyword">for</span>(<span class="hljs-keyword">int</span> i=<span class="hljs-number">0</span>; i&lt;length; i++) &#123;
         <span class="hljs-keyword">for</span>(<span class="hljs-keyword">int</span> j=<span class="hljs-number">0</span>; j&lt;width; j++) &#123;
            System.out.print(map[i][j]+<span class="hljs-string">" "</span>);
         &#125;
         System.out.println();
      &#125;

      <span class="hljs-comment">//走迷宫</span>
      getWay(map, <span class="hljs-number">1</span>, <span class="hljs-number">1</span>);

      <span class="hljs-comment">//行走路径</span>
      System.out.println(<span class="hljs-string">"行走路径"</span>);
      <span class="hljs-keyword">for</span>(<span class="hljs-keyword">int</span> i=<span class="hljs-number">0</span>; i&lt;length; i++) &#123;
         <span class="hljs-keyword">for</span>(<span class="hljs-keyword">int</span> j=<span class="hljs-number">0</span>; j&lt;width; j++) &#123;
            System.out.print(map[i][j]+<span class="hljs-string">" "</span>);
         &#125;
         System.out.println();
      &#125;

   &#125;

   <span class="hljs-comment">/**</span>
<span class="hljs-comment">    * 创建地图</span>
<span class="hljs-comment">    * <span class="hljs-doctag">@param</span> length 地图的长</span>
<span class="hljs-comment">    * <span class="hljs-doctag">@param</span> width 地图的宽</span>
<span class="hljs-comment">    * <span class="hljs-doctag">@return</span> 创建好的地图</span>
<span class="hljs-comment">    */</span>
   <span class="hljs-keyword">public</span> <span class="hljs-keyword">static</span> <span class="hljs-keyword">int</span>[][] getMap(<span class="hljs-keyword">int</span> length, <span class="hljs-keyword">int</span> width) &#123;
      <span class="hljs-keyword">int</span>[][] map = <span class="hljs-keyword">new</span> <span class="hljs-keyword">int</span>[length][width];
      <span class="hljs-comment">//先将第一行和最后一行设置为1（边界）</span>
      <span class="hljs-keyword">for</span>(<span class="hljs-keyword">int</span> i=<span class="hljs-number">0</span>; i&lt;width; i++) &#123;
         map[<span class="hljs-number">0</span>][i] = <span class="hljs-number">1</span>;
         map[length-<span class="hljs-number">1</span>][i] = <span class="hljs-number">1</span>;
      &#125;
      <span class="hljs-comment">//再将第一列和最后一列设置为1</span>
      <span class="hljs-keyword">for</span>(<span class="hljs-keyword">int</span> i=<span class="hljs-number">0</span>; i&lt;length; i++) &#123;
         map[i][<span class="hljs-number">0</span>] = <span class="hljs-number">1</span>;
         map[i][width-<span class="hljs-number">1</span>] = <span class="hljs-number">1</span>;
      &#125;
      <span class="hljs-keyword">return</span> map;
   &#125;

   <span class="hljs-comment">/**</span>
<span class="hljs-comment">    * 开始走迷宫</span>
<span class="hljs-comment">    * <span class="hljs-doctag">@param</span> map 地图</span>
<span class="hljs-comment">    * <span class="hljs-doctag">@param</span> i 起点横坐标</span>
<span class="hljs-comment">    * <span class="hljs-doctag">@param</span> j 七点纵坐标</span>
<span class="hljs-comment">    * <span class="hljs-doctag">@return</span> 能否走通，true能走通，false反之</span>
<span class="hljs-comment">    */</span>
   <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">static</span> <span class="hljs-keyword">boolean</span> <span class="hljs-title">getWay</span><span class="hljs-params">(<span class="hljs-keyword">int</span>[][] map, <span class="hljs-keyword">int</span> i, <span class="hljs-keyword">int</span> j)</span> </span>&#123;
      <span class="hljs-keyword">int</span> length= map.length;
      <span class="hljs-keyword">int</span> width = map[<span class="hljs-number">0</span>].length;
      <span class="hljs-comment">//假设右下角为终点</span>
      <span class="hljs-keyword">if</span>(map[length-<span class="hljs-number">2</span>][width-<span class="hljs-number">2</span>] == <span class="hljs-number">2</span>) &#123;
         <span class="hljs-comment">//走通了，返回true</span>
         <span class="hljs-keyword">return</span> <span class="hljs-keyword">true</span>;
      &#125; <span class="hljs-keyword">else</span> &#123;
         <span class="hljs-keyword">if</span>(map[i][j] == <span class="hljs-number">0</span>) &#123;
            <span class="hljs-comment">//假设改路能走通</span>
            map[i][j] = <span class="hljs-number">2</span>;
            <span class="hljs-comment">//行走策略 右-&gt;下-&gt;左-&gt;上</span>
            <span class="hljs-keyword">if</span>(getWay(map, i, j+<span class="hljs-number">1</span>)) &#123;
               <span class="hljs-keyword">return</span> <span class="hljs-keyword">true</span>;
            &#125;<span class="hljs-keyword">else</span> <span class="hljs-keyword">if</span>(getWay(map, i+<span class="hljs-number">1</span>, j)) &#123;
               <span class="hljs-keyword">return</span> <span class="hljs-keyword">true</span>;
            &#125;<span class="hljs-keyword">else</span> <span class="hljs-keyword">if</span>(getWay(map, i-<span class="hljs-number">1</span>, j)) &#123;
               <span class="hljs-keyword">return</span> <span class="hljs-keyword">true</span>;
            &#125;<span class="hljs-keyword">else</span> <span class="hljs-keyword">if</span>(getWay(map, i, j-<span class="hljs-number">1</span>)) &#123;
               <span class="hljs-keyword">return</span> <span class="hljs-keyword">true</span>;
            &#125;
            <span class="hljs-comment">//右下左上都走不通</span>
            map[i][j] = <span class="hljs-number">3</span>;
         &#125;<span class="hljs-keyword">else</span> &#123;
            <span class="hljs-comment">//改路已经被标记过了，不用再走了，直接返回false</span>
            <span class="hljs-keyword">return</span> <span class="hljs-keyword">false</span>;
         &#125;
      &#125;
      <span class="hljs-keyword">return</span> <span class="hljs-keyword">false</span>;
   &#125;
&#125;</code></pre>

<p>运行结果</p>
<pre><code class="hljs angelscript">地图如下
<span class="hljs-number">1</span> <span class="hljs-number">1</span> <span class="hljs-number">1</span> <span class="hljs-number">1</span> <span class="hljs-number">1</span> <span class="hljs-number">1</span> 
<span class="hljs-number">1</span> <span class="hljs-number">0</span> <span class="hljs-number">1</span> <span class="hljs-number">0</span> <span class="hljs-number">0</span> <span class="hljs-number">1</span> 
<span class="hljs-number">1</span> <span class="hljs-number">0</span> <span class="hljs-number">1</span> <span class="hljs-number">0</span> <span class="hljs-number">0</span> <span class="hljs-number">1</span> 
<span class="hljs-number">1</span> <span class="hljs-number">0</span> <span class="hljs-number">0</span> <span class="hljs-number">0</span> <span class="hljs-number">0</span> <span class="hljs-number">1</span> 
<span class="hljs-number">1</span> <span class="hljs-number">0</span> <span class="hljs-number">0</span> <span class="hljs-number">0</span> <span class="hljs-number">0</span> <span class="hljs-number">1</span> 
<span class="hljs-number">1</span> <span class="hljs-number">0</span> <span class="hljs-number">0</span> <span class="hljs-number">0</span> <span class="hljs-number">0</span> <span class="hljs-number">1</span> 
<span class="hljs-number">1</span> <span class="hljs-number">1</span> <span class="hljs-number">1</span> <span class="hljs-number">1</span> <span class="hljs-number">1</span> <span class="hljs-number">1</span> 
行走路径
<span class="hljs-number">1</span> <span class="hljs-number">1</span> <span class="hljs-number">1</span> <span class="hljs-number">1</span> <span class="hljs-number">1</span> <span class="hljs-number">1</span> 
<span class="hljs-number">1</span> <span class="hljs-number">2</span> <span class="hljs-number">1</span> <span class="hljs-number">0</span> <span class="hljs-number">0</span> <span class="hljs-number">1</span> 
<span class="hljs-number">1</span> <span class="hljs-number">2</span> <span class="hljs-number">1</span> <span class="hljs-number">0</span> <span class="hljs-number">0</span> <span class="hljs-number">1</span> 
<span class="hljs-number">1</span> <span class="hljs-number">2</span> <span class="hljs-number">2</span> <span class="hljs-number">2</span> <span class="hljs-number">2</span> <span class="hljs-number">1</span> 
<span class="hljs-number">1</span> <span class="hljs-number">0</span> <span class="hljs-number">0</span> <span class="hljs-number">0</span> <span class="hljs-number">2</span> <span class="hljs-number">1</span> 
<span class="hljs-number">1</span> <span class="hljs-number">0</span> <span class="hljs-number">0</span> <span class="hljs-number">0</span> <span class="hljs-number">2</span> <span class="hljs-number">1</span> 
<span class="hljs-number">1</span> <span class="hljs-number">1</span> <span class="hljs-number">1</span> <span class="hljs-number">1</span> <span class="hljs-number">1</span> <span class="hljs-number">1</span></code></pre>



<h2 id="5、八皇后问题"><a href="#5、八皇后问题" class="headerlink" title="5、八皇后问题"></a>5、八皇后问题</h2><p>八皇后问题，是一个古老而著名的问题，是<strong>回溯算法</strong>的典型案例。该问题是国际西洋棋棋手马克斯·贝瑟尔于1848年提出：在 8×8格的国际象棋上摆放八个皇后，使其不能互相攻击，即：任意两个皇后都<strong>不能处于同一行、同一列或同一斜线上</strong>，问有多少种摆法(92)。</p>
<p><strong>思路</strong></p>
<ul>
<li><p>将第一个皇后放在第一行第一列</p>
</li>
<li><p>将第二个皇后放在第二行第一列，判断是否会和其他皇后相互攻击，若会相互攻击，则将其放到第三列、第四列…知道不会相互攻击为止</p>
</li>
<li><p>将第三个皇后放在第三行第一列，判断是否会和其他皇后相互攻击，若会相互攻击，则将其放到第三列、第四列…知道不会相互攻击为止，并<strong>以此类推</strong>，<strong>在摆放的过程中，有可能会改动前面所放的皇后的位置</strong></p>
</li>
<li><p>当得到一个正确的解时，就会回溯到上一行，由此来找出第一个皇后在第一行第一列的所有解</p>
</li>
<li><p>再将第一个皇后放到第一行第二列，并重复以上四个步骤</p>
</li>
<li><p><strong>注意</strong>：</p>
<ul>
<li>棋盘本身应该是用二维数组表示，但是因为皇后所在的行数是固定的，所以可以简化为用一个一维数组来表示。其中的值代表皇后所在的列</li>
<li>数组下标代表皇后所在行数，所以判断是否在同一行列斜线上时，只需要判断是否在同一列和同一斜线上即可<ul>
<li>是否同列判断：值是否相同</li>
<li>是否同一斜线：行号-行号是否等于列号-列号，且<strong>列号相减要取绝对值</strong></li>
</ul>
</li>
</ul>
</li>
</ul>
<p><strong>代码</strong></p>
<pre><code class="hljs java"><span class="hljs-keyword">public</span> <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">Demo3</span> </span>&#123;
   <span class="hljs-comment">/**</span>
<span class="hljs-comment">    * 创建皇后所放位置的数组，数组的下标代表行号，数组中的值代表所在的列号</span>
<span class="hljs-comment">    */</span>
   <span class="hljs-keyword">static</span> <span class="hljs-keyword">int</span> sum = <span class="hljs-number">0</span>;
   <span class="hljs-keyword">int</span>  max = <span class="hljs-number">8</span>;
   <span class="hljs-keyword">int</span>[] arr = <span class="hljs-keyword">new</span> <span class="hljs-keyword">int</span>[max];
   <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">static</span> <span class="hljs-keyword">void</span> <span class="hljs-title">main</span><span class="hljs-params">(String[] args)</span> </span>&#123;
      Demo3 demo = <span class="hljs-keyword">new</span> Demo3();
      <span class="hljs-comment">//放入第一个皇后，开始求后面的皇后</span>
      demo.check(<span class="hljs-number">0</span>);
      System.out.println(<span class="hljs-string">"一共有"</span>+sum+<span class="hljs-string">"种放法"</span>);
   &#125;

   <span class="hljs-comment">/**</span>
<span class="hljs-comment">    * 打印数组元素</span>
<span class="hljs-comment">    */</span>
   <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">print</span><span class="hljs-params">()</span> </span>&#123;
      <span class="hljs-keyword">for</span>(<span class="hljs-keyword">int</span> i = <span class="hljs-number">0</span>; i&lt;arr.length; i++) &#123;
         System.out.print(arr[i] + <span class="hljs-string">" "</span>);
      &#125;
      sum++;
      System.out.println();
   &#125;

   <span class="hljs-comment">/**</span>
<span class="hljs-comment">    * 判断该位置的皇后与前面几个是否冲突</span>
<span class="hljs-comment">    * <span class="hljs-doctag">@param</span> position 需要判断的皇后的位置</span>
<span class="hljs-comment">    * <span class="hljs-doctag">@return</span> true代表冲突，false代表不冲突</span>
<span class="hljs-comment">    */</span>
   <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">boolean</span> <span class="hljs-title">judge</span><span class="hljs-params">(<span class="hljs-keyword">int</span> position)</span> </span>&#123;
      <span class="hljs-keyword">for</span>(<span class="hljs-keyword">int</span> i = <span class="hljs-number">0</span>; i&lt;position; i++) &#123;
         <span class="hljs-comment">//如果两个皇后在同一列或者同一斜线，就冲突</span>
         <span class="hljs-comment">//因为数组下标代表行数，所以不会存在皇后在同一行</span>
         <span class="hljs-comment">//所在行数-所在行数 如果等于 所在列数-所在列数，则两个皇后在同一斜线上</span>
         <span class="hljs-keyword">if</span>(arr[i] == arr[position] || (position-i) == Math.abs(arr[position]-arr[i])) &#123;
            <span class="hljs-keyword">return</span> <span class="hljs-keyword">true</span>;
         &#125;
      &#125;
      <span class="hljs-keyword">return</span> <span class="hljs-keyword">false</span>;
   &#125;

   <span class="hljs-comment">/**</span>
<span class="hljs-comment">    * 检查该皇后应放的位置</span>
<span class="hljs-comment">    * <span class="hljs-doctag">@param</span> queen 要检查的皇后</span>
<span class="hljs-comment">    */</span>
   <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">check</span><span class="hljs-params">(<span class="hljs-keyword">int</span> queen)</span> </span>&#123;
      <span class="hljs-keyword">if</span>(queen == max) &#123;
         <span class="hljs-comment">//所有的皇后都放好了，打印并返回</span>
         print();
         <span class="hljs-keyword">return</span>;
      &#125;
      <span class="hljs-comment">//把皇后放在每一列上，看哪些不会和之前的冲突</span>
      <span class="hljs-keyword">for</span>(<span class="hljs-keyword">int</span> i = <span class="hljs-number">0</span>; i&lt;max; i++) &#123;
         <span class="hljs-comment">//把第queen+1个皇后放在第i列</span>
         arr[queen] = i;
         <span class="hljs-keyword">if</span>(!judge(queen)) &#123;
            <span class="hljs-comment">//不冲突，就去放下一个皇后</span>
            check(queen+<span class="hljs-number">1</span>);
         &#125;
      &#125;
   &#125;
&#125;</code></pre>

<p>一共有92种放法，就不一一展示了</p>
<h1 id="五、排序"><a href="#五、排序" class="headerlink" title="五、排序"></a>五、排序</h1><h2 id="1、常见的排序算法"><a href="#1、常见的排序算法" class="headerlink" title="1、常见的排序算法"></a>1、常见的排序算法</h2><p><img src="https://nyimapicture.oss-cn-beijing.aliyuncs.com/img/20200619194904.png" srcset="/img/loading.gif" alt=""></p>
<h2 id="2、算法的时间复杂度"><a href="#2、算法的时间复杂度" class="headerlink" title="2、算法的时间复杂度"></a>2、算法的时间复杂度</h2><h3 id="时间频度和时间复杂度"><a href="#时间频度和时间复杂度" class="headerlink" title="时间频度和时间复杂度"></a>时间频度和时间复杂度</h3><p><strong>时间频度T(n)</strong></p>
<p>一个算法执行所耗费的时间，从理论上是不能算出来的，必须上机运行测试才能知道。但我们不可能也没有必要对每个算法都上机测试，只需知道哪个算法花费的时间多，哪个算法花费的时间少就可以了。并且一个算法花费的时间与算法中<strong>语句的执行次数成正比例</strong>，哪个算法中语句执行次数多，它花费时间就多。<strong>一个算法中的语句执行次数称为语句频度或时间频度</strong>。记为T(n)。</p>
<p><strong>时间复杂度O(n)</strong></p>
<p>一般情况下，算法中基本操作重复执行的次数是问题规模n的某个函数，用T(n)表示，若有某个辅助函数f(n),使得当n趋近于无穷大时，T（n)/f(n)的极限值为不等于零的常数，则称f(n)是T(n)的同数量级函数。记作T(n)=O(f(n)),称O(f(n)) 为算法的渐进时间复杂度，简称时间复杂度。</p>
<p>在T(n)=4n²-2n+2中，就有f(n)=n²，使得T（n)/f(n)的极限值为4，那么O(f(n))，也就是时间复杂度为O(n²)</p>
<ul>
<li><p>对于不是只有常数的时间复杂度<strong>忽略时间频度的系数、低次项常数</strong></p>
</li>
<li><p>对于只有常数的时间复杂度，将常数看为1</p>
</li>
</ul>
<h3 id="常见的时间复杂度"><a href="#常见的时间复杂度" class="headerlink" title="常见的时间复杂度"></a>常见的时间复杂度</h3><h4 id="常数阶-O-1"><a href="#常数阶-O-1" class="headerlink" title="常数阶 O(1)"></a>常数阶 O(1)</h4><pre><code class="hljs java"><span class="hljs-keyword">int</span> i = <span class="hljs-number">1</span>;
i++;</code></pre>

<p>无论代码执行了多少行，只要没有循环等复杂的结构，时间复杂度都是O(1)</p>
<h4 id="对数阶O-log2n"><a href="#对数阶O-log2n" class="headerlink" title="对数阶O(log2n)"></a>对数阶O(log<sub>2</sub>n)</h4><pre><code class="hljs java"><span class="hljs-keyword">while</span>(i&lt;n) &#123;
    i = i*<span class="hljs-number">2</span>;
&#125;</code></pre>

<p>此处i并不是依次递增到n，而是每次都以倍数增长。假设循环了x次后i大于n。则2<sup>x</sup> = n，x=log<sub>2</sub>n</p>
<h4 id="线性阶O-n"><a href="#线性阶O-n" class="headerlink" title="线性阶O(n)"></a>线性阶O(n)</h4><pre><code class="hljs java"><span class="hljs-keyword">for</span>(<span class="hljs-keyword">int</span> i = <span class="hljs-number">0</span>; i&lt;n; i++) &#123;
	i++;
&#125;</code></pre>

<p>这其中，循环体中的代码会执行n+1次，时间复杂度为O(n)</p>
<h4 id="线性对数阶O-nlog2n"><a href="#线性对数阶O-nlog2n" class="headerlink" title="线性对数阶O(nlog2n)"></a>线性对数阶O(nlog<sub>2</sub>n)</h4><pre><code class="hljs java"><span class="hljs-keyword">for</span>(<span class="hljs-keyword">int</span> i = <span class="hljs-number">0</span>; i&lt;n; i++) &#123;
    j = <span class="hljs-number">1</span>;
	<span class="hljs-keyword">while</span>(j&lt;n) &#123;
		j = j*<span class="hljs-number">2</span>;
	&#125;
&#125;</code></pre>

<p>此处外部为一个循环，循环了n次。内部也是一个循环，但内部f循环的时间复杂度是log<sub>2</sub>n</p>
<p>所以总体的时间复杂度为线性对数阶O(nlog<sub>2</sub>n)</p>
<h4 id="平方阶O-n2"><a href="#平方阶O-n2" class="headerlink" title="平方阶O(n2)"></a>平方阶O(n<sup>2</sup>)</h4><pre><code class="hljs java"><span class="hljs-keyword">for</span>(<span class="hljs-keyword">int</span> i = <span class="hljs-number">0</span>; i&lt;n; i++) &#123;
	<span class="hljs-keyword">for</span>(<span class="hljs-keyword">int</span> j = <span class="hljs-number">0</span>; j&lt;n; j++) &#123;
		<span class="hljs-comment">//循环体</span>
	&#125;
&#125;</code></pre>

<h4 id="立方阶O-n3"><a href="#立方阶O-n3" class="headerlink" title="立方阶O(n3)"></a>立方阶O(n<sup>3</sup>)</h4><pre><code class="hljs java"><span class="hljs-keyword">for</span>(<span class="hljs-keyword">int</span> i = <span class="hljs-number">0</span>; i&lt;n; i++) &#123;
	<span class="hljs-keyword">for</span>(<span class="hljs-keyword">int</span> j = <span class="hljs-number">0</span>; j&lt;n; j++) &#123;
		<span class="hljs-keyword">for</span>(<span class="hljs-keyword">int</span> k = <span class="hljs-number">0</span>; k&lt;n; k++) &#123;
			<span class="hljs-comment">//循环体</span>
		&#125;
	&#125;
&#125;</code></pre>

<p>可以看出平方阶、立方阶的复杂度主要是否循环嵌套了几层来决定的</p>
<h2 id="3、排序算法的时间复杂度"><a href="#3、排序算法的时间复杂度" class="headerlink" title="3、排序算法的时间复杂度"></a>3、排序算法的时间复杂度</h2><table>
<thead>
<tr>
<th>排序算法</th>
<th>平均时间</th>
<th>最差时间</th>
<th>稳定性</th>
<th>空间复杂度</th>
<th>备注</th>
</tr>
</thead>
<tbody><tr>
<td>冒泡排序</td>
<td>O(n<sup>2</sup>)</td>
<td>O(n<sup>2</sup>)</td>
<td>稳定</td>
<td>O(1)</td>
<td>n较小时好</td>
</tr>
<tr>
<td>交换排序</td>
<td>O(n<sup>2</sup>)</td>
<td>O(n<sup>2</sup>)</td>
<td>不稳定</td>
<td>O(1)</td>
<td>n较小时好</td>
</tr>
<tr>
<td>选择排序</td>
<td>O(n<sup>2</sup>)</td>
<td>O(n<sup>2</sup>)</td>
<td>不稳定</td>
<td>O(1)</td>
<td>n较小时好</td>
</tr>
<tr>
<td>插入排序</td>
<td>O(n<sup>2</sup>)</td>
<td>O(n<sup>2</sup>)</td>
<td>稳定</td>
<td>O(1)</td>
<td>大部分已有序时好</td>
</tr>
<tr>
<td>基数排序</td>
<td>O(n*k)</td>
<td>O(n*k)</td>
<td>稳定</td>
<td>O(n)</td>
<td>二维数组（桶）、一维数组（桶中首元素的位置）</td>
</tr>
<tr>
<td>希尔排序</td>
<td>O(nlogn)</td>
<td>O(n<sup>s</sup>)(1&lt;s&lt;2)</td>
<td>不稳定</td>
<td>O(1)</td>
<td>s是所选分组</td>
</tr>
<tr>
<td>快速排序</td>
<td>O(nlogn)</td>
<td>O(n<sup>2</sup>)</td>
<td>不稳定</td>
<td>O(logn)</td>
<td>n较大时好</td>
</tr>
<tr>
<td>归并排序</td>
<td>O(nlogn)</td>
<td>O(nlogn)</td>
<td>稳定</td>
<td>O(1)</td>
<td>n较大时好</td>
</tr>
<tr>
<td>堆排序</td>
<td>O(nlogn)</td>
<td>O(nlogn)</td>
<td>不稳定</td>
<td>O(1)</td>
<td>n较大时好</td>
</tr>
</tbody></table>
<h2 id="4、冒泡排序"><a href="#4、冒泡排序" class="headerlink" title="4、冒泡排序"></a>4、冒泡排序</h2><p><strong>算法步骤</strong></p>
<ul>
<li><p>比较相邻的元素。如果第一个比第二个大，就交换他们两个。</p>
</li>
<li><p>对每一对相邻元素作同样的工作，从开始第一对到结尾的最后一对。这步做完后，<strong>最后的元素会是最大的数</strong>。</p>
</li>
<li><p>针对所有的元素重复以上的步骤，<strong>除了最后一个</strong>。</p>
</li>
<li><p>持续每次对越来越少的元素重复上面的步骤，直到没有任何一对数字需要比较。</p>
</li>
<li><p>一共进行了<strong>数组元素个数-1</strong>次大循环，且每次大循环中需要比较的元素越来越少。</p>
</li>
<li><p>优化：如果在某次大循环，发现没有发生交换，则证明已经有序。</p>
</li>
</ul>
<p><strong>代码</strong></p>
<pre><code class="hljs java"><span class="hljs-keyword">public</span> <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">Demo1</span> </span>&#123;
   <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">static</span> <span class="hljs-keyword">void</span> <span class="hljs-title">main</span><span class="hljs-params">(String[] args)</span> </span>&#123;
      <span class="hljs-keyword">int</span>[] arr = &#123;<span class="hljs-number">4</span>, <span class="hljs-number">5</span>, <span class="hljs-number">1</span>, <span class="hljs-number">6</span>, <span class="hljs-number">2</span>&#125;;
      <span class="hljs-keyword">for</span>(<span class="hljs-keyword">int</span> i = <span class="hljs-number">1</span>; i&lt;arr.length; i++) &#123;
         <span class="hljs-comment">//定义一个标识，来记录这趟大循环是否发生了交换</span>
         <span class="hljs-keyword">boolean</span> flag = <span class="hljs-keyword">true</span>;
         <span class="hljs-comment">//只需要比较前length-i个数</span>
         <span class="hljs-comment">//每次排序会确定一个最大的元素</span>
         <span class="hljs-keyword">for</span>(<span class="hljs-keyword">int</span> j = <span class="hljs-number">0</span>; j&lt;arr.length-i; j++) &#123;
            <span class="hljs-keyword">if</span>(arr[j] &gt; arr[j+<span class="hljs-number">1</span>]) &#123;
               <span class="hljs-keyword">int</span> temp = arr[j];
               arr[j] = arr[j+<span class="hljs-number">1</span>];
               arr[j+<span class="hljs-number">1</span>] = temp;
               <span class="hljs-comment">//发生了交换，标识改为false</span>
               flag = <span class="hljs-keyword">false</span>;
            &#125;
         &#125;
         <span class="hljs-comment">//如果这次循环没发生交换，直接停止循环</span>
         <span class="hljs-keyword">if</span>(flag) &#123;
            <span class="hljs-keyword">break</span>;
         &#125;
      &#125;
      <span class="hljs-keyword">for</span>(<span class="hljs-keyword">int</span> i : arr) &#123;
         System.out.println(i);
      &#125;
   &#125;
&#125;</code></pre>



<h2 id="5、选择排序"><a href="#5、选择排序" class="headerlink" title="5、选择排序"></a>5、选择排序</h2><p><strong>算法步骤</strong></p>
<ul>
<li><p>遍历整个数组，找到最小（大）的元素，放到数组的起始位置。</p>
</li>
<li><p>再遍历剩下的数组，找到剩下元素中的最小（大）元素，放到数组的第二个位置。</p>
</li>
<li><p>重复以上步骤，直到排序完成。</p>
</li>
<li><p>一共需要遍历数组元素个数-1次，当找到第二大（小）的元素时，可以停止。这时最后一个元素必是最大（小）元素。</p>
</li>
</ul>
<p><strong>代码</strong></p>
<pre><code class="hljs java"><span class="hljs-keyword">public</span> <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">Demo2</span> </span>&#123;
	<span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">static</span> <span class="hljs-keyword">void</span> <span class="hljs-title">main</span><span class="hljs-params">(String[] args)</span> </span>&#123;
		<span class="hljs-keyword">int</span>[] arr = &#123;<span class="hljs-number">3</span>, <span class="hljs-number">1</span>, <span class="hljs-number">6</span>, <span class="hljs-number">10</span>, <span class="hljs-number">2</span>&#125;;

		<span class="hljs-comment">//从第0个元素开始比较，一共循环length-1次，最后一个无须进行排序</span>
		<span class="hljs-keyword">for</span>(<span class="hljs-keyword">int</span> i = <span class="hljs-number">0</span>; i&lt;arr.length-<span class="hljs-number">1</span>; i++) &#123;
			<span class="hljs-comment">//保存最小元素的下标</span>
			<span class="hljs-keyword">int</span> min = i;
			<span class="hljs-comment">//将该元素与剩下的元素比较，找出最小元素的下标</span>
			<span class="hljs-keyword">for</span>(<span class="hljs-keyword">int</span> j = i+<span class="hljs-number">1</span>; j&lt;arr.length; j++) &#123;
				<span class="hljs-comment">//保存最小元素的下标</span>
				<span class="hljs-keyword">if</span>(arr[j] &lt; arr[min]) &#123;
					min = j;
				&#125;
			&#125;
			<span class="hljs-comment">//交换元素</span>
			<span class="hljs-comment">//如果不是arr[i]不是最小的元素，就交换</span>
			<span class="hljs-keyword">if</span>(min != i) &#123;
				<span class="hljs-keyword">int</span> temp;
				temp = arr[i];
				arr[i] = arr[min];
				arr[min] = temp;
			&#125;
		&#125;

		<span class="hljs-keyword">for</span>(<span class="hljs-keyword">int</span> i : arr) &#123;
			System.out.println(i);
		&#125;
	&#125;
&#125;</code></pre>



<h2 id="6、插入排序"><a href="#6、插入排序" class="headerlink" title="6、插入排序"></a>6、插入排序</h2><p><strong>算法步骤</strong></p>
<ul>
<li>将待排序序列第一个元素看做一个<strong>有序序列</strong>，把第二个元素到最后一个元素当成是<strong>未排序序列</strong>。</li>
<li>从头到尾依次扫描未排序序列，将扫描到的每个元素插入有序序列的适当位置。（如果待插入的元素与有序序列中的某个元素相等，则将待插入元素插入到相等元素的后面。</li>
</ul>
<p><strong>代码</strong></p>
<pre><code class="hljs java"><span class="hljs-keyword">public</span> <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">Demo3</span> </span>&#123;
   <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">static</span> <span class="hljs-keyword">void</span> <span class="hljs-title">main</span><span class="hljs-params">(String[] args)</span> </span>&#123;
      <span class="hljs-keyword">int</span>[] arr = &#123;<span class="hljs-number">3</span>, <span class="hljs-number">1</span>, <span class="hljs-number">6</span>, <span class="hljs-number">10</span>, <span class="hljs-number">2</span>&#125;;
      <span class="hljs-comment">//从数组的第二个元素开始选择位置插入</span>
      <span class="hljs-comment">//因为第一个元素已经放入了有序数组中</span>
      <span class="hljs-keyword">for</span>(<span class="hljs-keyword">int</span> i = <span class="hljs-number">1</span>; i&lt;arr.length; i++) &#123;
         <span class="hljs-comment">//保存该位置上元素的值,后面移动元素可能会覆盖该位置上元素的值</span>
         <span class="hljs-keyword">int</span> temp = arr[i];
         <span class="hljs-comment">//变量j用于遍历前面的有序数组</span>
         <span class="hljs-keyword">int</span> j = i;
         <span class="hljs-keyword">while</span> (j&gt;<span class="hljs-number">0</span> &amp;&amp; temp&lt;arr[j-<span class="hljs-number">1</span>]) &#123;
            <span class="hljs-comment">//如果有序数组中的元素大于temp，则后移一个位置</span>
            arr[j] = arr[j-<span class="hljs-number">1</span>];
            j--;
         &#125;

         <span class="hljs-comment">//j选择所指位置就是待插入的位置</span>
         <span class="hljs-keyword">if</span>(j != i) &#123;
            arr[j] = temp;
         &#125;
      &#125;
      <span class="hljs-keyword">for</span>(<span class="hljs-keyword">int</span> i : arr) &#123;
         System.out.println(i);
      &#125;
   &#125;
&#125;</code></pre>



<h2 id="7、希尔排序"><a href="#7、希尔排序" class="headerlink" title="7、希尔排序"></a>7、希尔排序</h2><p><strong>回顾：插入排序存在的问题</strong></p>
<p>当最后一个元素为整个数组的最小元素时，需要将前面的有序数组中的每个元素都向后移一位，这样是非常花时间的。</p>
<p>所以有了希尔排序来帮我们将数组从无序变为整体有序再变为有序。</p>
<p><strong>算法步骤</strong></p>
<ul>
<li><p>选择一个增量序列t1（一般是数组长度/2），t2（一般是一个分组长度/2），……，tk，<strong>其中 ti &gt; tj</strong>, tk = 1；</p>
</li>
<li><p>按增量序列个数 k，对序列进行 k 趟排序；</p>
</li>
<li><p>每趟排序，根据对应的增量 ti，将待排序列分割成若干长度为 m 的子序列，分别对各子表进行直接插入排序。仅增量因子为 1 时，整个序列作为一个表来处理，表长度即为整个序列的长度。</p>
</li>
</ul>
<p><strong>示意图</strong></p>
<p><img src="https://nyimapicture.oss-cn-beijing.aliyuncs.com/img/20200621122846.png" srcset="/img/loading.gif" alt=""></p>
<p><strong>代码</strong></p>
<pre><code class="hljs java"><span class="hljs-keyword">public</span> <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">Demo4</span> </span>&#123;
   <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">static</span> <span class="hljs-keyword">void</span> <span class="hljs-title">main</span><span class="hljs-params">(String[] args)</span> </span>&#123;
      <span class="hljs-keyword">int</span>[] arr = &#123;<span class="hljs-number">3</span>, <span class="hljs-number">6</span>, <span class="hljs-number">1</span>, <span class="hljs-number">4</span>, <span class="hljs-number">5</span>, <span class="hljs-number">8</span>, <span class="hljs-number">2</span>, <span class="hljs-number">0</span>&#125;;
      <span class="hljs-keyword">int</span> temp;
      <span class="hljs-comment">//将数组分为gap组,每个组内部进行插入排序</span>
      <span class="hljs-keyword">for</span>(<span class="hljs-keyword">int</span> gap = arr.length/<span class="hljs-number">2</span>; gap&gt;<span class="hljs-number">0</span>; gap /= <span class="hljs-number">2</span>) &#123;
         <span class="hljs-comment">//i用来指向未排序数组的首个元素</span>
         <span class="hljs-keyword">for</span>(<span class="hljs-keyword">int</span> i = gap; i&lt;arr.length; i++) &#123;
            temp = arr[i];
            <span class="hljs-keyword">int</span> j = i;
            <span class="hljs-comment">//找到temp应该插入的位置,需要先判断数组是否越界</span>
            <span class="hljs-keyword">while</span> (j-gap&gt;=<span class="hljs-number">0</span> &amp;&amp; temp&lt;arr[j-gap]) &#123;
               arr[j] = arr[j-gap];
               j -= gap;
            &#125;

            <span class="hljs-keyword">if</span>(j != i) &#123;
               arr[j] = temp;
            &#125;
         &#125;
      &#125;

      <span class="hljs-keyword">for</span>(<span class="hljs-keyword">int</span> i : arr) &#123;
         System.out.println(i);
      &#125;
   &#125;
&#125;</code></pre>



<h2 id="8、快速排序"><a href="#8、快速排序" class="headerlink" title="8、快速排序"></a>8、快速排序</h2><p><strong>算法步骤</strong></p>
<ul>
<li>从数列中挑出一个元素，称为 “基准”（pivot）;</li>
<li>重新排序数列，所有元素比基准值小的摆放在基准前面，所有元素比基准值大的摆在基准的后面（相同的数可以到任一边）。在这个分区退出之后，该基准就处于数列的中间位置。这个称为分区（partition）操作；</li>
<li>递归地（recursive）把小于基准值元素的子数列和大于基准值元素的子数列排序；</li>
</ul>
<p><strong>代码</strong></p>
<pre><code class="hljs java"><span class="hljs-keyword">public</span> <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">Demo5</span> </span>&#123;
   <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">static</span> <span class="hljs-keyword">void</span> <span class="hljs-title">main</span><span class="hljs-params">(String[] args)</span> </span>&#123;
      <span class="hljs-keyword">int</span>[] arr = &#123;<span class="hljs-number">8</span>, <span class="hljs-number">12</span>, <span class="hljs-number">19</span>, -<span class="hljs-number">1</span>, <span class="hljs-number">45</span>, <span class="hljs-number">0</span>, <span class="hljs-number">14</span>, <span class="hljs-number">4</span>, <span class="hljs-number">11</span>&#125;;
      QuickSort sort = <span class="hljs-keyword">new</span> QuickSort();
      sort.quickSort(arr);
      <span class="hljs-keyword">for</span>(<span class="hljs-keyword">int</span> i : arr) &#123;
         System.out.println(i);
      &#125;
   &#125;
&#125;

<span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">QuickSort</span> </span>&#123;

   <span class="hljs-comment">/**</span>
<span class="hljs-comment">    * 快速排序</span>
<span class="hljs-comment">    * <span class="hljs-doctag">@param</span> arr 待排序的数组</span>
<span class="hljs-comment">    */</span>
   <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">quickSort</span><span class="hljs-params">(<span class="hljs-keyword">int</span>[] arr)</span> </span>&#123;
      <span class="hljs-keyword">if</span>(arr == <span class="hljs-keyword">null</span> || arr.length&lt;=<span class="hljs-number">1</span>) &#123;
         <span class="hljs-keyword">return</span>;
      &#125;

      quickSort(arr, <span class="hljs-number">0</span>, arr.length-<span class="hljs-number">1</span>);
   &#125;

   <span class="hljs-comment">/**</span>
<span class="hljs-comment">    *</span>
<span class="hljs-comment">    * <span class="hljs-doctag">@param</span> arr 待排序的数组</span>
<span class="hljs-comment">    * <span class="hljs-doctag">@param</span> left 左侧开始下标</span>
<span class="hljs-comment">    * <span class="hljs-doctag">@param</span> right 右侧开始下标</span>
<span class="hljs-comment">    */</span>
   <span class="hljs-function"><span class="hljs-keyword">private</span> <span class="hljs-keyword">void</span> <span class="hljs-title">quickSort</span><span class="hljs-params">(<span class="hljs-keyword">int</span>[] arr, <span class="hljs-keyword">int</span> left, <span class="hljs-keyword">int</span> right)</span> </span>&#123;
      <span class="hljs-comment">//如果分区元素小于等于一个，就返回</span>
      <span class="hljs-keyword">if</span>(right &lt;= left) &#123;
         <span class="hljs-keyword">return</span>;
      &#125;

      <span class="hljs-comment">//得到基数下标</span>
      <span class="hljs-keyword">int</span> partition = partition(arr, left, right);

      <span class="hljs-comment">//递归左右两个分区,因为每次是以左边的第一个数为基数，所以右边分区递归需要在partition的右侧开始</span>
      quickSort(arr, left, partition);
      quickSort(arr, partition+<span class="hljs-number">1</span>, right);
   &#125;


   <span class="hljs-comment">/**</span>
<span class="hljs-comment">    * 返回基准下标</span>
<span class="hljs-comment">    * <span class="hljs-doctag">@param</span> arr 待排序的数组</span>
<span class="hljs-comment">    * <span class="hljs-doctag">@param</span> left 左侧开始下标</span>
<span class="hljs-comment">    * <span class="hljs-doctag">@param</span> right 右侧开始下标</span>
<span class="hljs-comment">    * <span class="hljs-doctag">@return</span> 中间值的下标</span>
<span class="hljs-comment">    */</span>
    <span class="hljs-function"><span class="hljs-keyword">private</span> <span class="hljs-keyword">int</span> <span class="hljs-title">partition</span><span class="hljs-params">(<span class="hljs-keyword">int</span>[] arr, <span class="hljs-keyword">int</span> left, <span class="hljs-keyword">int</span> right)</span> </span>&#123;
      <span class="hljs-comment">//以该分区最左边的数为基数</span>
      <span class="hljs-keyword">int</span> pivot = arr[left];

      <span class="hljs-keyword">while</span>(left &lt; right) &#123;
         <span class="hljs-comment">//右边下标开始向左移动，找到小于基数的值时停止</span>
         <span class="hljs-keyword">while</span>(right&gt;left &amp;&amp; arr[right] &gt;= pivot) &#123;
            right--;
         &#125;
         <span class="hljs-comment">//交换数值，此时pivot保存了arr[left]的值，所以不会丢失</span>
         arr[left] = arr[right];

         <span class="hljs-comment">//左边下标开始移动，找到大于基数的值时停止</span>
         <span class="hljs-keyword">while</span>(left&lt;right &amp;&amp; arr[left] &lt;= pivot) &#123;
            left++;
         &#125;
         <span class="hljs-comment">//交换数值</span>
         arr[right] = arr[left];
         <span class="hljs-comment">//基数插入到合适的位置</span>
         arr[left] = pivot;
      &#125;

      <span class="hljs-comment">//返回基数下标</span>
      <span class="hljs-keyword">return</span> left;
   &#125;
&#125;</code></pre>



<h2 id="9、归并排序"><a href="#9、归并排序" class="headerlink" title="9、归并排序"></a>9、归并排序</h2><p><strong>算法步骤</strong></p>
<p>归并排序用到了<strong>分而治之</strong>的思想，其难点是<strong>治</strong></p>
<ul>
<li>申请空间，使其大小为两个已经排序序列之和，该空间用来存放合并后的序列</li>
<li>设定两个指针，最初位置分别为两个已经排序序列的起始位置</li>
<li>比较两个指针所指向的元素，选择相对小的元素放入到合并空间，并移动指针到下一位置</li>
<li>重复上一步 直到<strong>某一指针达到序列尾</strong></li>
<li>将另一序列剩下的所有元素直接复制到合并序列尾</li>
</ul>
<p><img src="https://nyimapicture.oss-cn-beijing.aliyuncs.com/img/20200621201843.png" srcset="/img/loading.gif" alt=""></p>
<p><img src="https://nyimapicture.oss-cn-beijing.aliyuncs.com/img/20200621201859.png" srcset="/img/loading.gif" alt=""></p>
<p><img src="https://nyimapicture.oss-cn-beijing.aliyuncs.com/img/20200621201925.png" srcset="/img/loading.gif" alt=""></p>
<p><img src="https://nyimapicture.oss-cn-beijing.aliyuncs.com/img/20200621202006.png" srcset="/img/loading.gif" alt=""></p>
<p><strong>此时第二个序列的指针已经到达末尾，则将第一个序列中剩下的元素全部放入和合并序列末尾</strong></p>
<p><img src="https://nyimapicture.oss-cn-beijing.aliyuncs.com/img/20200621202124.png" srcset="/img/loading.gif" alt=""></p>
<p><strong>代码</strong></p>
<pre><code class="hljs java"><span class="hljs-keyword">public</span> <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">Demo6</span> </span>&#123;
   <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">static</span> <span class="hljs-keyword">void</span> <span class="hljs-title">main</span><span class="hljs-params">(String[] args)</span> </span>&#123;
      <span class="hljs-keyword">int</span>[] arr = &#123;<span class="hljs-number">1</span>, <span class="hljs-number">5</span>, <span class="hljs-number">6</span>, <span class="hljs-number">3</span>, <span class="hljs-number">2</span>, <span class="hljs-number">8</span>, <span class="hljs-number">7</span>, <span class="hljs-number">4</span>&#125;;
      MergeSort mergeSort = <span class="hljs-keyword">new</span> MergeSort(arr.length);
      mergeSort.mergeSort(arr, <span class="hljs-number">0</span>, arr.length-<span class="hljs-number">1</span>);
      <span class="hljs-keyword">for</span>(<span class="hljs-keyword">int</span> a : arr) &#123;
         System.out.println(a);
      &#125;
   &#125;
&#125;

<span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">MergeSort</span> </span>&#123;
   <span class="hljs-comment">/**</span>
<span class="hljs-comment">    * 临时数组，用于合并时用于存放元素</span>
<span class="hljs-comment">    */</span>
   <span class="hljs-keyword">int</span>[] temp;


   <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-title">MergeSort</span><span class="hljs-params">()</span> </span>&#123;
   &#125;

   <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-title">MergeSort</span><span class="hljs-params">(<span class="hljs-keyword">int</span> length)</span> </span>&#123;
      temp = <span class="hljs-keyword">new</span> <span class="hljs-keyword">int</span>[length];
   &#125;

   <span class="hljs-comment">/**</span>
<span class="hljs-comment">    * 将分解的序列进行合并，合并的同时完成排序</span>
<span class="hljs-comment">    * <span class="hljs-doctag">@param</span> arr 待合并的数组</span>
<span class="hljs-comment">    * <span class="hljs-doctag">@param</span> left 数组左边界</span>
<span class="hljs-comment">    * <span class="hljs-doctag">@param</span> right 数组右边界</span>
<span class="hljs-comment">    */</span>
   <span class="hljs-function"><span class="hljs-keyword">private</span> <span class="hljs-keyword">void</span> <span class="hljs-title">merge</span><span class="hljs-params">(<span class="hljs-keyword">int</span>[] arr, <span class="hljs-keyword">int</span> left, <span class="hljs-keyword">int</span> right)</span> </span>&#123;
      <span class="hljs-comment">//两个序列的分界点</span>
      <span class="hljs-keyword">int</span> mid = (left+right)/<span class="hljs-number">2</span>;
      <span class="hljs-comment">//temp数组中插入的位置</span>
      <span class="hljs-keyword">int</span> tempLeft = <span class="hljs-number">0</span>;
      <span class="hljs-keyword">int</span> arrLeft = left;
      <span class="hljs-comment">//第二个序列的首元素下标</span>
      <span class="hljs-keyword">int</span> arrRight = mid+<span class="hljs-number">1</span>;

      <span class="hljs-keyword">while</span>(arrLeft&lt;=mid &amp;&amp; arrRight&lt;=right) &#123;
         <span class="hljs-comment">//如果第一个序列的元素小于第二序列的元素，就将其放入temp中</span>
         <span class="hljs-keyword">if</span>(arr[arrLeft] &lt;= arr[arrRight]) &#123;
            temp[tempLeft] = arr[arrLeft];
            arrLeft++;
         &#125;<span class="hljs-keyword">else</span> &#123;
            temp[tempLeft] = arr[arrRight];
            arrRight++;
         &#125;
         tempLeft++;
      &#125;


      <span class="hljs-comment">//将不为空的序列中的元素依次放入temp中</span>
      <span class="hljs-keyword">while</span> (arrLeft &lt;= mid) &#123;
         temp[tempLeft] = arr[arrLeft];
         tempLeft++;
         arrLeft++;
      &#125;

      <span class="hljs-keyword">while</span> (arrRight &lt;= right) &#123;
         temp[tempLeft] = arr[arrRight];
         tempLeft++;
         arrRight++;
      &#125;

      <span class="hljs-comment">//将临时数组中的元素放回数组arr中</span>
      tempLeft = <span class="hljs-number">0</span>;
      arrLeft = left;
      <span class="hljs-keyword">while</span> (arrLeft &lt;= right) &#123;
         arr[arrLeft] = temp[tempLeft];
         arrLeft++;
         tempLeft++;
      &#125;
   &#125;

   <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">mergeSort</span><span class="hljs-params">(<span class="hljs-keyword">int</span>[] arr, <span class="hljs-keyword">int</span> left, <span class="hljs-keyword">int</span> right)</span> </span>&#123;
      <span class="hljs-keyword">int</span> mid = (left+right)/<span class="hljs-number">2</span>;
      <span class="hljs-keyword">if</span>(left &lt; right) &#123;
         mergeSort(arr, left, mid);
         mergeSort(arr, mid+<span class="hljs-number">1</span>, right);
         merge(arr, left, right);
      &#125;
   &#125;
&#125;</code></pre>



<h2 id="10、基数排序"><a href="#10、基数排序" class="headerlink" title="10、基数排序"></a>10、基数排序</h2><p><strong>算法步骤</strong></p>
<ul>
<li>将所有待比较数值（正整数）统一为同样的数位长度，<strong>数位较短的数前面补零</strong></li>
<li>从最低位开始，依次进行一次排序</li>
<li>从最低位排序一直到最高位（个位-&gt;十位-&gt;百位-&gt;…-&gt;最高位）排序完成以后, 数列就变成一个有序序列</li>
<li>需要我们获得最大数的位数<ul>
<li>可以通过将<strong>最大数变为String类型</strong>，再求得它的长度即可</li>
</ul>
</li>
</ul>
<p><img src="https://nyimapicture.oss-cn-beijing.aliyuncs.com/img/20200621225309.png" srcset="/img/loading.gif" alt=""></p>
<p><strong>按照个位，放到对应的桶中</strong></p>
<p><img src="https://nyimapicture.oss-cn-beijing.aliyuncs.com/img/20200621225354.png" srcset="/img/loading.gif" alt=""></p>
<p><strong>依次取出，同一个桶中有多个元素的，先放入的先取出</strong></p>
<p><img src="https://nyimapicture.oss-cn-beijing.aliyuncs.com/img/20200621225456.png" srcset="/img/loading.gif" alt=""></p>
<p><strong>再按照十位，放到对应的桶中，个位数前面补0</strong></p>
<p><img src="https://nyimapicture.oss-cn-beijing.aliyuncs.com/img/20200621225609.png" srcset="/img/loading.gif" alt=""></p>
<p><strong>再依次取出桶中元素</strong></p>
<p><img src="https://nyimapicture.oss-cn-beijing.aliyuncs.com/img/20200621225802.png" srcset="/img/loading.gif" alt=""></p>
<p><strong>再按照百位，放到对应的桶中，个位数和十位数前面补0</strong></p>
<p><img src="https://nyimapicture.oss-cn-beijing.aliyuncs.com/img/20200621225742.png" srcset="/img/loading.gif" alt=""></p>
<p><strong>再依次取出桶中元素</strong></p>
<p><img src="https://nyimapicture.oss-cn-beijing.aliyuncs.com/img/20200621225802.png" srcset="/img/loading.gif" alt=""><strong>再按照千位，放到对应的桶中，个位数、十位数和百位数前面补0</strong></p>
<p><img src="https://nyimapicture.oss-cn-beijing.aliyuncs.com/img/20200621225900.png" srcset="/img/loading.gif" alt=""><strong>当所有的数都在0号桶时，依次取出元素，这时顺序即为排好后的顺序</strong></p>
<p><img src="https://nyimapicture.oss-cn-beijing.aliyuncs.com/img/20200621225954.png" srcset="/img/loading.gif" alt=""></p>
<p><strong>代码</strong></p>
<pre><code class="hljs java"><span class="hljs-keyword">public</span> <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">Demo7</span> </span>&#123;
   <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">static</span> <span class="hljs-keyword">void</span> <span class="hljs-title">main</span><span class="hljs-params">(String[] args)</span> </span>&#123;
      <span class="hljs-keyword">int</span>[] arr = &#123;<span class="hljs-number">43</span>, <span class="hljs-number">52</span>, <span class="hljs-number">1</span>, <span class="hljs-number">89</span>, <span class="hljs-number">190</span>&#125;;
      CardinalitySort cardinalitySort = <span class="hljs-keyword">new</span> CardinalitySort();
      cardinalitySort.sort(arr);
      <span class="hljs-keyword">for</span>(<span class="hljs-keyword">int</span> a : arr) &#123;
         System.out.println(a);
      &#125;
   &#125;
&#125;

<span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">CardinalitySort</span> </span>&#123;
   <span class="hljs-comment">/**</span>
<span class="hljs-comment">    * 进行基数排序</span>
<span class="hljs-comment">    * <span class="hljs-doctag">@param</span> arr 待排序的数组</span>
<span class="hljs-comment">    */</span>
   <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">sort</span><span class="hljs-params">(<span class="hljs-keyword">int</span>[] arr)</span> </span>&#123;
      <span class="hljs-comment">//创建一个二维数组，用于表示桶</span>
      <span class="hljs-comment">//桶的个数固定为10个（个位是0~9），最大容量由数组的长度决定</span>
      <span class="hljs-keyword">int</span> maxSize = arr.length;
      <span class="hljs-keyword">int</span>[][] bucket = <span class="hljs-keyword">new</span> <span class="hljs-keyword">int</span>[<span class="hljs-number">10</span>][maxSize];
      <span class="hljs-comment">//用于记录每个桶中有多少个元素</span>
      <span class="hljs-keyword">int</span>[] elementCounts = <span class="hljs-keyword">new</span> <span class="hljs-keyword">int</span>[<span class="hljs-number">10</span>];

      <span class="hljs-comment">//获得该数组中最大元素的位数</span>
      <span class="hljs-keyword">int</span> maxDigits = getMaxDigits(arr);

      <span class="hljs-comment">//将数组中的元素放入桶中, step是在求数组位数时，需要除以的倍数</span>
      <span class="hljs-keyword">for</span> (<span class="hljs-keyword">int</span> time = <span class="hljs-number">1</span>, step = <span class="hljs-number">1</span>; time&lt;=maxDigits; time++, step *= <span class="hljs-number">10</span>) &#123;
         <span class="hljs-keyword">for</span>(<span class="hljs-keyword">int</span> i = <span class="hljs-number">0</span>; i&lt;arr.length; i++) &#123;
            <span class="hljs-comment">//取出所需的位数</span>
            <span class="hljs-keyword">int</span> digits = arr[i] / step % <span class="hljs-number">10</span>;
            <span class="hljs-comment">//放入到对应的桶中 [digits]代表桶的编号</span>
            <span class="hljs-comment">//[elementCounts[digits]]代表放入该桶的位置</span>
            bucket[digits][elementCounts[digits]] = arr[i];
            <span class="hljs-comment">//桶中元素个数+1</span>
            elementCounts[digits]++;
         &#125;

         <span class="hljs-comment">//将桶中的元素重新放回到数组中</span>
         <span class="hljs-comment">//用于记录应该放入原数组的哪个位置</span>
         <span class="hljs-keyword">int</span> index = <span class="hljs-number">0</span>;
         <span class="hljs-keyword">for</span>(<span class="hljs-keyword">int</span> i = <span class="hljs-number">0</span>; i&lt;<span class="hljs-number">10</span>; i++) &#123;
            <span class="hljs-comment">//从桶中按放入顺序依次取出元素，放入原数组</span>
            <span class="hljs-keyword">int</span> position = <span class="hljs-number">0</span>;
            <span class="hljs-comment">//桶中有元素才取出</span>
            <span class="hljs-keyword">while</span> (elementCounts[i] &gt; <span class="hljs-number">0</span>) &#123;
               arr[index] = bucket[i][position];
               position++;
               elementCounts[i]--;
               index++;
            &#125;
         &#125;
      &#125;

   &#125;

   <span class="hljs-comment">/**</span>
<span class="hljs-comment">    * 得到该数组中最大元素的位数</span>
<span class="hljs-comment">    * <span class="hljs-doctag">@param</span> arr 待求数组</span>
<span class="hljs-comment">    * <span class="hljs-doctag">@return</span> 最大元素的位数</span>
<span class="hljs-comment">    */</span>
   <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">int</span> <span class="hljs-title">getMaxDigits</span><span class="hljs-params">(<span class="hljs-keyword">int</span>[] arr)</span> </span>&#123;
      <span class="hljs-keyword">int</span> max = arr[<span class="hljs-number">0</span>];
      <span class="hljs-keyword">for</span>(<span class="hljs-keyword">int</span> i=<span class="hljs-number">1</span>; i&lt;arr.length; i++) &#123;
         <span class="hljs-keyword">if</span>(arr[i] &gt; max) &#123;
            max = arr[i];
         &#125;
      &#125;
      <span class="hljs-comment">//将最大值转为字符串，它的长度就是它的位数</span>
      <span class="hljs-keyword">int</span> digits = (max + <span class="hljs-string">""</span>).length();
      <span class="hljs-keyword">return</span> digits;
   &#125;
&#125;</code></pre>



<h2 id="11、堆排序"><a href="#11、堆排序" class="headerlink" title="11、堆排序"></a>11、堆排序</h2><p><strong>基本介绍</strong></p>
<ul>
<li><p>堆排序是利用堆这种数据结构而设计的一种排序算法，堆排序是一种选择排序，它的最坏，最好，平均时间复杂度均为 <strong>O(nlogn)</strong>，它也是不稳定排序</p>
</li>
<li><p>堆是具有以下性质的<strong>完全二叉树</strong>：</p>
<ul>
<li>每个结点的值都大于或等于其左右孩子结点的值，称为<strong>大顶堆</strong><ul>
<li>注意 : 没有要求结点的左孩子的值和右孩子的值的大小关系</li>
</ul>
</li>
<li>每个结点的值都小于或等于其左右孩子结点的值，称为<strong>小顶堆</strong></li>
</ul>
</li>
<li><p>一般升序排序采用大顶堆，降序排列使用小顶堆</p>
</li>
</ul>
<p><img src="https://nyimapicture.oss-cn-beijing.aliyuncs.com/img/20200727191935.png" srcset="/img/loading.gif" alt=""></p>
<p><img src="https://nyimapicture.oss-cn-beijing.aliyuncs.com/img/20200727191922.png" srcset="/img/loading.gif" alt=""></p>
<p><strong>排序思路</strong></p>
<ul>
<li>堆是一种树结构，但是排序中会将堆进行<strong>顺序存储</strong>（变为数组结构）</li>
<li>将无序序列构建成一个堆，根据升序降序需求选择大顶堆或小顶堆</li>
<li>将堆顶元素与末尾元素交换，将最大元素&quot;沉&quot;到数组末端</li>
<li>重新调整结构，使其满足堆定义，然后继续交换堆顶元素与当前末尾元素，反复执行调整+交换步骤，直到整个序列有序</li>
</ul>
<p><strong>实现代码</strong></p>
<pre><code class="hljs java"><span class="hljs-comment">/**</span>
<span class="hljs-comment"> * <span class="hljs-doctag">@author</span> Chen Panwen</span>
<span class="hljs-comment"> * <span class="hljs-doctag">@data</span> 2020/7/27 16:19</span>
<span class="hljs-comment"> */</span>
<span class="hljs-keyword">public</span> <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">Demo2</span> </span>&#123;
   <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">static</span> <span class="hljs-keyword">void</span> <span class="hljs-title">main</span><span class="hljs-params">(String[] args)</span> </span>&#123;
      <span class="hljs-keyword">int</span>[] arr = &#123;<span class="hljs-number">4</span>, <span class="hljs-number">6</span>, <span class="hljs-number">8</span>, <span class="hljs-number">5</span>, <span class="hljs-number">9</span>&#125;;
      <span class="hljs-comment">//堆排序</span>
      heapSort(arr);
      System.out.println(<span class="hljs-string">"堆排序后结果"</span>);
      System.out.println(Arrays.toString(arr));
   &#125;

   <span class="hljs-comment">/**</span>
<span class="hljs-comment">    * 堆排序（升序排序）</span>
<span class="hljs-comment">    * <span class="hljs-doctag">@param</span> arr 待排序数组</span>
<span class="hljs-comment">    */</span>
   <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">static</span> <span class="hljs-keyword">void</span> <span class="hljs-title">heapSort</span><span class="hljs-params">(<span class="hljs-keyword">int</span>[] arr)</span> </span>&#123;
      <span class="hljs-keyword">for</span>(<span class="hljs-keyword">int</span> i=arr.length-<span class="hljs-number">1</span>; i&gt;=<span class="hljs-number">0</span>; i--) &#123;
         <span class="hljs-comment">//将数组调整为大顶堆，长度为未排序数组的长度</span>
         <span class="hljs-keyword">for</span>(<span class="hljs-keyword">int</span> j=arr.length/<span class="hljs-number">2</span>-<span class="hljs-number">1</span>; j&gt;=<span class="hljs-number">0</span>; j--) &#123;
            adjustHeap(arr, j, i+<span class="hljs-number">1</span>);
         &#125;
         <span class="hljs-comment">//调整后，数组首元素就为最大值，与为元素交换</span>
         <span class="hljs-keyword">int</span> temp = arr[i];
         arr[i] = arr[<span class="hljs-number">0</span>];
         arr[<span class="hljs-number">0</span>] = temp;
      &#125;
   &#125;

   <span class="hljs-comment">/**</span>
<span class="hljs-comment">    * 将无序数组进行调整，将其调整为大顶堆</span>
<span class="hljs-comment">    * <span class="hljs-doctag">@param</span> arr 待调整的数组</span>
<span class="hljs-comment">    * <span class="hljs-doctag">@param</span> index 非叶子节点的索引</span>
<span class="hljs-comment">    * <span class="hljs-doctag">@param</span> length 待调整数组的长度</span>
<span class="hljs-comment">    */</span>
   <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">static</span> <span class="hljs-keyword">void</span> <span class="hljs-title">adjustHeap</span><span class="hljs-params">(<span class="hljs-keyword">int</span>[] arr, <span class="hljs-keyword">int</span> index, <span class="hljs-keyword">int</span> length)</span> </span>&#123;
      <span class="hljs-comment">//保存非叶子节点的值，最后需要进行交换操作</span>
      <span class="hljs-keyword">int</span> temp = arr[index];

      <span class="hljs-comment">//进行调整操作</span>
      <span class="hljs-comment">//index*2+1代表其左子树</span>
      <span class="hljs-keyword">for</span>(<span class="hljs-keyword">int</span> i = index*<span class="hljs-number">2</span>+<span class="hljs-number">1</span>; i&lt;length; i = i*<span class="hljs-number">2</span>+<span class="hljs-number">1</span>) &#123;
         <span class="hljs-comment">//如果存在右子树，且右子树的值大于左子树，就让索引指向其右子树</span>
         <span class="hljs-keyword">if</span>(i+<span class="hljs-number">1</span>&lt;length &amp;&amp; arr[i] &lt; arr[i+<span class="hljs-number">1</span>]) &#123;
            i++;
         &#125;
         <span class="hljs-comment">//如果右子树的值大于该节点的值就交换，同时改变索引index的值</span>
         <span class="hljs-keyword">if</span>(arr[i] &gt; arr[index]) &#123;
            arr[index] = arr[i];
            index = i;
         &#125;<span class="hljs-keyword">else</span> &#123;
            <span class="hljs-keyword">break</span>;
         &#125;
         <span class="hljs-comment">//调整完成后，将temp放到最终调整后的位置</span>
         arr[index] = temp;
      &#125;
   &#125;
&#125;</code></pre>

<p><strong>运行结果</strong></p>
<pre><code class="hljs angelscript">堆排序后结果
[<span class="hljs-number">4</span>, <span class="hljs-number">5</span>, <span class="hljs-number">6</span>, <span class="hljs-number">8</span>, <span class="hljs-number">9</span>]</code></pre>





<h1 id="六、查找"><a href="#六、查找" class="headerlink" title="六、查找"></a>六、查找</h1><h2 id="1、线性查找"><a href="#1、线性查找" class="headerlink" title="1、线性查找"></a>1、线性查找</h2><p>线性查找是一种非常简单的查找方式。查找思路是：从数组的一个元素出发，一个个地和要查找的值进行比较，如果发现有相同的元素就返回该元素的下标。反之返回-1（未找到）</p>
<pre><code class="hljs java"><span class="hljs-keyword">public</span> <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">Demo1</span> </span>&#123;
   <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">static</span> <span class="hljs-keyword">void</span> <span class="hljs-title">main</span><span class="hljs-params">(String[] args)</span> </span>&#123;
      <span class="hljs-keyword">int</span>[] arr = &#123;<span class="hljs-number">1</span>, <span class="hljs-number">11</span>, -<span class="hljs-number">1</span>, <span class="hljs-number">0</span>, <span class="hljs-number">55</span>&#125;;
      <span class="hljs-keyword">int</span> result = seqSearch(arr, <span class="hljs-number">1</span>);
      <span class="hljs-keyword">if</span>(result == -<span class="hljs-number">1</span>) &#123;
         System.out.println(<span class="hljs-string">"数组中没有该元素"</span>);
      &#125;<span class="hljs-keyword">else</span> &#123;
         System.out.println(<span class="hljs-string">"该元素在数组的下标是："</span> + result);
      &#125;
   &#125;

   <span class="hljs-comment">/**</span>
<span class="hljs-comment">    * 线性查找</span>
<span class="hljs-comment">    * <span class="hljs-doctag">@param</span> arr 查找的数组</span>
<span class="hljs-comment">    * <span class="hljs-doctag">@param</span> num 待查找的数字</span>
<span class="hljs-comment">    * <span class="hljs-doctag">@return</span> 数字的索引</span>
<span class="hljs-comment">    */</span>
   <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">static</span> <span class="hljs-keyword">int</span> <span class="hljs-title">seqSearch</span><span class="hljs-params">(<span class="hljs-keyword">int</span>[] arr, <span class="hljs-keyword">int</span> num)</span> </span>&#123;
      <span class="hljs-keyword">for</span>(<span class="hljs-keyword">int</span> i = <span class="hljs-number">0</span>; i&lt;arr.length; i++) &#123;
         <span class="hljs-keyword">if</span>(arr[i] == num) &#123;
            <span class="hljs-keyword">return</span> i;
         &#125;
      &#125;
      <span class="hljs-keyword">return</span> -<span class="hljs-number">1</span>;
   &#125;
&#125;</code></pre>



<h2 id="2、二分查找"><a href="#2、二分查找" class="headerlink" title="2、二分查找"></a>2、二分查找</h2><p>进行二分查找的数组必须为<strong>有序数组</strong></p>
<ul>
<li>设置一个指向中间元素下标的变量mid，mid=(left + right)/2</li>
<li>让要查找的元素和数组mid下标的元素进行比较<ul>
<li>如果查找的元素大于arr[mid]，则left变为mid后面一个元素的下标</li>
<li>如果查找的元素小于arr[mid]，则right变为mid前一个元素的下标</li>
<li>如果查找的元素等于arr[mid]，则mid就是要查找元素所在的位置</li>
</ul>
</li>
<li>当left &gt; rigth时，说明元素不在该数组中</li>
</ul>
<pre><code class="hljs java"><span class="hljs-keyword">public</span> <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">Demo2</span> </span>&#123;
   <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">static</span> <span class="hljs-keyword">void</span> <span class="hljs-title">main</span><span class="hljs-params">(String[] args)</span> </span>&#123;
      <span class="hljs-comment">//进行二分查找的数组必须是有序</span>
      <span class="hljs-keyword">int</span>[] arr = &#123;-<span class="hljs-number">1</span>, <span class="hljs-number">0</span>, <span class="hljs-number">2</span>, <span class="hljs-number">11</span>, <span class="hljs-number">30</span>&#125;;
      <span class="hljs-keyword">int</span> result = binarySearch(arr, <span class="hljs-number">11</span>);
      <span class="hljs-keyword">if</span>(result == -<span class="hljs-number">1</span>) &#123;
         System.out.println(<span class="hljs-string">"未找到该元素"</span>);
      &#125;<span class="hljs-keyword">else</span> &#123;
         System.out.println(<span class="hljs-string">"该元素的下标是："</span> + result);
      &#125;
   &#125;

   <span class="hljs-comment">/**</span>
<span class="hljs-comment">    * 二分查找</span>
<span class="hljs-comment">    * <span class="hljs-doctag">@param</span> arr 要查找的有序数组</span>
<span class="hljs-comment">    * <span class="hljs-doctag">@param</span> num 要查找的数字</span>
<span class="hljs-comment">    * <span class="hljs-doctag">@return</span> 对应数字的下标</span>
<span class="hljs-comment">    */</span>
   <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">static</span> <span class="hljs-keyword">int</span> <span class="hljs-title">binarySearch</span><span class="hljs-params">(<span class="hljs-keyword">int</span>[] arr, <span class="hljs-keyword">int</span> num)</span> </span>&#123;
      <span class="hljs-keyword">int</span> left = <span class="hljs-number">0</span>;
      <span class="hljs-keyword">int</span> right = arr.length-<span class="hljs-number">1</span>;
      <span class="hljs-keyword">while</span>(left &lt;= right) &#123;
         <span class="hljs-comment">//防止溢出</span>
         <span class="hljs-keyword">int</span> mid = (right - left)/<span class="hljs-number">2</span> + left;
         <span class="hljs-comment">//如果要查找的值大于中间位置的值，说明要查找的值在右边部分</span>
         <span class="hljs-keyword">if</span>(arr[mid] &lt; num) &#123;
            left = mid + <span class="hljs-number">1</span>;
         &#125;<span class="hljs-keyword">else</span> <span class="hljs-keyword">if</span>(arr[mid] &gt; num) &#123;
            <span class="hljs-comment">//如果要查找的值小于中间位置的值</span>
            <span class="hljs-comment">//说明要查找的值在左边部分</span>
            right = mid - <span class="hljs-number">1</span>;
         &#125;<span class="hljs-keyword">else</span> &#123;
            <span class="hljs-comment">//找到了该元素</span>
            <span class="hljs-keyword">return</span> mid;
         &#125;
      &#125;
      <span class="hljs-keyword">return</span> -<span class="hljs-number">1</span>;
   &#125;
&#125;</code></pre>



<p><strong>但是有可能要查找的元素有多个</strong>。这时就需要在找到一个元素后，不要立即返回，而是<strong>扫描其左边和右边的元素</strong>，将所有相同元素的下标保存到一个数组中，然后一起返回</p>
<pre><code class="hljs java"><span class="hljs-keyword">public</span> <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">Demo2</span> </span>&#123;
   <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">static</span> <span class="hljs-keyword">void</span> <span class="hljs-title">main</span><span class="hljs-params">(String[] args)</span> </span>&#123;
      <span class="hljs-keyword">int</span>[] arr = &#123;-<span class="hljs-number">1</span>, <span class="hljs-number">0</span>, <span class="hljs-number">11</span>, <span class="hljs-number">11</span>, <span class="hljs-number">11</span>, <span class="hljs-number">11</span>, <span class="hljs-number">30</span>&#125;;
      <span class="hljs-comment">//进行二分查找的数组必须是有序</span>
      Arrays.sort(arr);
      List&lt;Integer&gt; result = binarySearch(arr, <span class="hljs-number">11</span>);
      <span class="hljs-keyword">if</span>(result.size() == <span class="hljs-number">0</span>) &#123;
         System.out.println(<span class="hljs-string">"未找到该元素"</span>);
      &#125;<span class="hljs-keyword">else</span> &#123;
         <span class="hljs-keyword">for</span>(Integer index : result) &#123;
            System.out.println(index);
         &#125;
      &#125;
   &#125;

   <span class="hljs-comment">/**</span>
<span class="hljs-comment">    * 二分查找（可以查找重复元素的下标）</span>
<span class="hljs-comment">    * <span class="hljs-doctag">@param</span> arr 要查找的有序数组</span>
<span class="hljs-comment">    * <span class="hljs-doctag">@param</span> num 要查找的数字</span>
<span class="hljs-comment">    * <span class="hljs-doctag">@return</span> 保存了所有该值元素所在的位置</span>
<span class="hljs-comment">    */</span>
   <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">static</span> List&lt;Integer&gt; <span class="hljs-title">binarySearch</span><span class="hljs-params">(<span class="hljs-keyword">int</span>[] arr, <span class="hljs-keyword">int</span> num)</span> </span>&#123;
      <span class="hljs-keyword">int</span> left = <span class="hljs-number">0</span>;
      <span class="hljs-keyword">int</span> right = arr.length-<span class="hljs-number">1</span>;
      <span class="hljs-keyword">int</span> mid;
      <span class="hljs-comment">//用户保存查找值下标</span>
      List&lt;Integer&gt; positionList = <span class="hljs-keyword">new</span> ArrayList&lt;&gt;();
      <span class="hljs-keyword">while</span>(left &lt;= right) &#123;
         mid = (left + right)/<span class="hljs-number">2</span>;
         <span class="hljs-comment">//如果要查找的值大于中间位置的值，说明要查找的值在右边部分</span>
         <span class="hljs-keyword">if</span>(arr[mid] &lt; num) &#123;
            left = mid + <span class="hljs-number">1</span>;
         &#125;<span class="hljs-keyword">else</span> <span class="hljs-keyword">if</span>(arr[mid] &gt; num) &#123;
            <span class="hljs-comment">//如果要查找的值小于中间位置的值</span>
            <span class="hljs-comment">//说明要查找的值在左边部分</span>
            right = mid - <span class="hljs-number">1</span>;
         &#125;<span class="hljs-keyword">else</span> &#123;
            <span class="hljs-comment">//将下标存入到集合中</span>
            positionList.add(mid);
            <span class="hljs-comment">//用于遍历mid左边的相同元素</span>
            <span class="hljs-keyword">int</span> leftIndex = mid - <span class="hljs-number">1</span>;
            <span class="hljs-keyword">while</span>(leftIndex &gt; <span class="hljs-number">0</span> &amp;&amp; arr[leftIndex] == num) &#123;
               positionList.add(leftIndex);
               leftIndex--;
            &#125;

            <span class="hljs-keyword">int</span> rightIndex = mid + <span class="hljs-number">1</span>;
            <span class="hljs-keyword">while</span>(rightIndex &lt; right &amp;&amp; arr[rightIndex] == num) &#123;
               positionList.add(rightIndex);
               rightIndex++;
            &#125;

            <span class="hljs-keyword">return</span> positionList;
         &#125;
      &#125;

      <span class="hljs-keyword">return</span> positionList;
   &#125;
&#125;</code></pre>



<h2 id="3、插值查找"><a href="#3、插值查找" class="headerlink" title="3、插值查找"></a>3、插值查找</h2><p>在二分查找中，如果我们 要找的元素位于数组的最前端或者最后段，这时的查找效率是很低的。所以在二分查找至上，引入了插值查找，也是一种<strong>基于有序数组</strong>的查找方式</p>
<p>插值查找与二分查找的区别是：插值查找使用了一种<strong>自适应</strong>算法，用这种算法来计算mid。</p>
<p>mid的值在两种查找算法中的求法：</p>
<ul>
<li>二分查找：mid = (left + right)/2</li>
<li>插值查找：<strong>mid = left + (right - left) * (num - arr[left]) / (arr[right] - arr[left])</strong><ul>
<li>其中num为要查找的那个值</li>
</ul>
</li>
</ul>
<pre><code class="hljs java"><span class="hljs-keyword">public</span> <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">Demo3</span> </span>&#123;
   <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">static</span> <span class="hljs-keyword">void</span> <span class="hljs-title">main</span><span class="hljs-params">(String[] args)</span> </span>&#123;
      <span class="hljs-keyword">int</span>[] arr = &#123;-<span class="hljs-number">1</span>, -<span class="hljs-number">1</span>, <span class="hljs-number">0</span>, <span class="hljs-number">11</span>, <span class="hljs-number">11</span>, <span class="hljs-number">11</span>, <span class="hljs-number">11</span>, <span class="hljs-number">30</span>&#125;;
      <span class="hljs-comment">//进行二分查找的数组必须是有序</span>
      Arrays.sort(arr);
      List&lt;Integer&gt; result = insertSearch(arr, <span class="hljs-number">30</span>);
      <span class="hljs-keyword">if</span>(result.size() == <span class="hljs-number">0</span>) &#123;
         System.out.println(<span class="hljs-string">"未找到该元素"</span>);
      &#125;<span class="hljs-keyword">else</span> &#123;
         <span class="hljs-keyword">for</span>(Integer index : result) &#123;
            System.out.println(index);
         &#125;
      &#125;
   &#125;

   <span class="hljs-comment">/**</span>
<span class="hljs-comment">    * 插值查找查找（可以查找重复元素的下标）</span>
<span class="hljs-comment">    * <span class="hljs-doctag">@param</span> arr 要查找的有序数组</span>
<span class="hljs-comment">    * <span class="hljs-doctag">@param</span> num 要查找的数字</span>
<span class="hljs-comment">    * <span class="hljs-doctag">@return</span> 保存了所有该值元素所在的位置</span>
<span class="hljs-comment">    */</span>
   <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">static</span> List&lt;Integer&gt; <span class="hljs-title">insertSearch</span><span class="hljs-params">(<span class="hljs-keyword">int</span>[] arr, <span class="hljs-keyword">int</span> num)</span> </span>&#123;
      List&lt;Integer&gt; positionList = <span class="hljs-keyword">new</span> ArrayList&lt;&gt;();
      <span class="hljs-keyword">int</span> left = <span class="hljs-number">0</span>;
      <span class="hljs-keyword">int</span> right = arr.length - <span class="hljs-number">1</span>;
      <span class="hljs-keyword">int</span> mid;
      <span class="hljs-keyword">while</span>(left&lt;=right) &#123;
         <span class="hljs-comment">//插值查找的自适应算法</span>
         mid = left+(right-left)*(num-arr[left])/(arr[right]-arr[left]);
         <span class="hljs-keyword">if</span>(arr[mid] &gt; num) &#123;
            right = mid - <span class="hljs-number">1</span>;
         &#125;<span class="hljs-keyword">else</span> <span class="hljs-keyword">if</span>(arr[mid] &lt; num) &#123;
            left = mid + <span class="hljs-number">1</span>;
         &#125;<span class="hljs-keyword">else</span> &#123;
            <span class="hljs-comment">//找到了该元素的位置</span>
            positionList.add(mid);
         &#125;

         <span class="hljs-comment">//继续查找mid附近值相同的元素</span>
         <span class="hljs-keyword">int</span> leftIndex = mid - <span class="hljs-number">1</span>;
         <span class="hljs-keyword">while</span>(leftIndex &gt;=<span class="hljs-number">0</span> &amp;&amp; arr[leftIndex] == num) &#123;
            positionList.add(leftIndex);
            leftIndex++;
         &#125;
         <span class="hljs-keyword">int</span> rightIndex = mid + <span class="hljs-number">1</span>;
         <span class="hljs-keyword">while</span> (rightIndex &lt;= right &amp;&amp; arr[rightIndex] == num) &#123;
            positionList.add(rightIndex);
            rightIndex++;
         &#125;
         <span class="hljs-keyword">return</span> positionList;
      &#125;
      <span class="hljs-keyword">return</span> positionList;
   &#125;
&#125;</code></pre>



<h1 id="七、哈希表"><a href="#七、哈希表" class="headerlink" title="七、哈希表"></a>七、哈希表</h1><h2 id="1、基本介绍"><a href="#1、基本介绍" class="headerlink" title="1、基本介绍"></a>1、基本介绍</h2><p>散列表（Hash table，也叫哈希表），是根据<strong>关键码值</strong>(Key value)而直接进行访问的数据结构。也就是说，它通过把关键码值映射到表中一个位置来访问记录，以加快查找的速度。这个映射函数叫做散列函数，存放记录的数组叫做散列表。</p>
<p><img src="https://nyimapicture.oss-cn-beijing.aliyuncs.com/img/20200715134934.png" srcset="/img/loading.gif" alt=""></p>
<p>哈希表是一种将<strong>数组与链表相结合</strong>的数据结构</p>
<pre><code class="hljs java"><span class="hljs-keyword">public</span> <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">Demo5</span> </span>&#123;
   <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">static</span> <span class="hljs-keyword">void</span> <span class="hljs-title">main</span><span class="hljs-params">(String[] args)</span> </span>&#123;
      <span class="hljs-comment">//创建学生</span>
      Student student1 = <span class="hljs-keyword">new</span> Student(<span class="hljs-number">1</span>, <span class="hljs-string">"Nyima"</span>);
      Student student2 = <span class="hljs-keyword">new</span> Student(<span class="hljs-number">2</span>, <span class="hljs-string">"Lulu"</span>);
      Student student6 = <span class="hljs-keyword">new</span> Student(<span class="hljs-number">6</span>, <span class="hljs-string">"WenWen"</span>);
      HashTab hashTab = <span class="hljs-keyword">new</span> HashTab(<span class="hljs-number">5</span>);
      hashTab.add(student1);
      hashTab.add(student2);
      hashTab.add(student6);
      hashTab.traverse();
      <span class="hljs-comment">//通过id查找学生信息</span>
      hashTab.findStuById(<span class="hljs-number">6</span>);
   &#125;
&#125;

<span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">Student</span> </span>&#123;
    <span class="hljs-keyword">int</span> id;
    String name;
   Student next;

   <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-title">Student</span><span class="hljs-params">(<span class="hljs-keyword">int</span> id, String name)</span> </span>&#123;
      <span class="hljs-keyword">this</span>.id = id;
      <span class="hljs-keyword">this</span>.name = name;
   &#125;

   <span class="hljs-meta">@Override</span>
   <span class="hljs-function"><span class="hljs-keyword">public</span> String <span class="hljs-title">toString</span><span class="hljs-params">()</span> </span>&#123;
      <span class="hljs-keyword">return</span> <span class="hljs-string">"Student&#123;"</span> +
            <span class="hljs-string">"id="</span> + id +
            <span class="hljs-string">", name='"</span> + name + <span class="hljs-string">'\''</span> +
            <span class="hljs-string">'&#125;'</span>;
   &#125;
&#125;

<span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">LinkedList</span> </span>&#123;
   <span class="hljs-keyword">private</span> Student head = <span class="hljs-keyword">new</span> Student(-<span class="hljs-number">1</span>, <span class="hljs-string">""</span>);

   <span class="hljs-comment">/**</span>
<span class="hljs-comment">    * 插入学生信息</span>
<span class="hljs-comment">    * <span class="hljs-doctag">@param</span> student 插入学生的信息</span>
<span class="hljs-comment">    */</span>
   <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">add</span><span class="hljs-params">(Student student)</span> </span>&#123;
      <span class="hljs-keyword">if</span>(head.next == <span class="hljs-keyword">null</span>) &#123;
         head.next = student;
         <span class="hljs-keyword">return</span>;
      &#125;

      Student temp = head.next;
      <span class="hljs-keyword">while</span>(temp.next != <span class="hljs-keyword">null</span>) &#123;
         temp = temp.next;
      &#125;

      temp.next = student;
   &#125;

   <span class="hljs-comment">/**</span>
<span class="hljs-comment">    * 遍历链表</span>
<span class="hljs-comment">    */</span>
   <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">traverse</span><span class="hljs-params">()</span> </span>&#123;
      <span class="hljs-keyword">if</span>(head.next == <span class="hljs-keyword">null</span>) &#123;
         System.out.println(<span class="hljs-string">"链表为空"</span>);
         <span class="hljs-keyword">return</span>;
      &#125;

      Student temp = head;
      <span class="hljs-keyword">while</span>(temp.next != <span class="hljs-keyword">null</span>) &#123;
         temp = temp.next;
         System.out.print(temp + <span class="hljs-string">" "</span>);
      &#125;
      <span class="hljs-comment">//换行</span>
      System.out.println();
   &#125;

   <span class="hljs-comment">/**</span>
<span class="hljs-comment">    * 通过id查找学生信息</span>
<span class="hljs-comment">    * <span class="hljs-doctag">@param</span> id 学生id</span>
<span class="hljs-comment">    */</span>
   <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">findStuById</span><span class="hljs-params">(<span class="hljs-keyword">int</span> id)</span> </span>&#123;
      <span class="hljs-keyword">if</span>(head.next == <span class="hljs-keyword">null</span>) &#123;
         System.out.println(<span class="hljs-string">"链表为空"</span>);
         <span class="hljs-keyword">return</span>;
      &#125;

      Student temp = head;
      <span class="hljs-keyword">while</span>(temp.next != <span class="hljs-keyword">null</span>) &#123;
         temp = temp.next;
         <span class="hljs-keyword">if</span>(temp.id == id) &#123;
            <span class="hljs-comment">//找到学生，打印学生信息</span>
            System.out.println(<span class="hljs-string">"该学生信息："</span> + temp);
            <span class="hljs-keyword">return</span>;
         &#125;
      &#125;

      System.out.println(<span class="hljs-string">"未找到该学生信息"</span>);
   &#125;
&#125;

<span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">HashTab</span> </span>&#123;
   <span class="hljs-keyword">private</span> LinkedList[] linkedLists;
   <span class="hljs-keyword">private</span> <span class="hljs-keyword">final</span> <span class="hljs-keyword">int</span> size;

   <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-title">HashTab</span><span class="hljs-params">(<span class="hljs-keyword">int</span> size)</span> </span>&#123;
      <span class="hljs-keyword">this</span>.size = size;
      <span class="hljs-comment">//初始化散列表</span>
      linkedLists = <span class="hljs-keyword">new</span> LinkedList[size];
      <span class="hljs-comment">//初始化每个链表，不然会抛出空指针异常</span>
      <span class="hljs-keyword">for</span>(<span class="hljs-keyword">int</span> i=<span class="hljs-number">0</span>; i&lt;<span class="hljs-keyword">this</span>.size; i++) &#123;
         <span class="hljs-comment">//对每个链表进行初始化操作</span>
         linkedLists[i] = <span class="hljs-keyword">new</span> LinkedList();
      &#125;
   &#125;

   <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">add</span><span class="hljs-params">(Student student)</span> </span>&#123;
      <span class="hljs-keyword">int</span> hashId = getHash(student.id);
      linkedLists[hashId].add(student);
   &#125;

   <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">traverse</span><span class="hljs-params">()</span> </span>&#123;
      <span class="hljs-keyword">for</span>(<span class="hljs-keyword">int</span> i=<span class="hljs-number">0</span> ; i&lt;size; i++) &#123;
         linkedLists[i].traverse();
      &#125;
   &#125;

   <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">findStuById</span><span class="hljs-params">(<span class="hljs-keyword">int</span> id)</span> </span>&#123;
      <span class="hljs-keyword">int</span> hashId = getHash(id);
      linkedLists[hashId].findStuById(id);
   &#125;

   <span class="hljs-comment">/**</span>
<span class="hljs-comment">    * 散列函数，获得散列值</span>
<span class="hljs-comment">    * <span class="hljs-doctag">@param</span> id 学生的id</span>
<span class="hljs-comment">    * <span class="hljs-doctag">@return</span> 对应的散列值</span>
<span class="hljs-comment">    */</span>
   <span class="hljs-function"><span class="hljs-keyword">private</span> <span class="hljs-keyword">int</span> <span class="hljs-title">getHash</span><span class="hljs-params">(<span class="hljs-keyword">int</span> id)</span> </span>&#123;
      <span class="hljs-keyword">return</span> id % size;
   &#125;
&#125;</code></pre>



<h1 id="八、树结构"><a href="#八、树结构" class="headerlink" title="八、树结构"></a>八、树结构</h1><h2 id="1、二叉树"><a href="#1、二叉树" class="headerlink" title="1、二叉树"></a>1、二叉树</h2><h3 id="为什么需要树"><a href="#为什么需要树" class="headerlink" title="为什么需要树"></a>为什么需要树</h3><ul>
<li>数组的查找效率高，但是插入效率低。</li>
<li>链表的插入效率高，查找效率低。</li>
</ul>
<p>需要一种数据结构来平衡查找与插入效率，使得查找速度和插入速度都能得到提升，因此有了树这种数据结构。</p>
<h3 id="树的基本概念"><a href="#树的基本概念" class="headerlink" title="树的基本概念"></a>树的基本概念</h3><p><img src="https://nyimapicture.oss-cn-beijing.aliyuncs.com/img/20200715135230.png" srcset="/img/loading.gif" alt=""></p>
<h3 id="二叉树的基本概念"><a href="#二叉树的基本概念" class="headerlink" title="二叉树的基本概念"></a>二叉树的基本概念</h3><p>每个节点<strong>最多只能有两个子节点</strong>的一种形式称为二叉树</p>
<p><img src="https://nyimapicture.oss-cn-beijing.aliyuncs.com/img/20200715135439.png" srcset="/img/loading.gif" alt=""></p>
<p><img src="https://nyimapicture.oss-cn-beijing.aliyuncs.com/img/20200715135455.png" srcset="/img/loading.gif" alt=""></p>
<p><img src="https://nyimapicture.oss-cn-beijing.aliyuncs.com/img/20200715135512.png" srcset="/img/loading.gif" alt=""></p>
<h3 id="满二叉树"><a href="#满二叉树" class="headerlink" title="满二叉树"></a>满二叉树</h3><p>如果该二叉树的所有<strong>叶子节点</strong>都在<strong>最后一层</strong>，并且结点总数= <strong>2<sup>n</sup> -1</strong> , n为层数，则我们称为满二叉树。</p>
<p><img src="https://nyimapicture.oss-cn-beijing.aliyuncs.com/img/20200715135734.png" srcset="/img/loading.gif" alt=""></p>
<h3 id="完全二叉树"><a href="#完全二叉树" class="headerlink" title="完全二叉树"></a>完全二叉树</h3><p>如果该二叉树的所有<strong>叶子节点</strong>都在<strong>最后一层</strong>或者<strong>倒数第二层</strong>，而且最后一层的叶子节点在左边连续，倒数第二层的叶子节点在右边连续，我们称为完全二叉树</p>
<p><img src="https://nyimapicture.oss-cn-beijing.aliyuncs.com/img/20200715135950.png" srcset="/img/loading.gif" alt=""></p>
<p><img src="https://nyimapicture.oss-cn-beijing.aliyuncs.com/img/20200715135917.png" srcset="/img/loading.gif" alt=""></p>
<h3 id="二叉树的遍历"><a href="#二叉树的遍历" class="headerlink" title="二叉树的遍历"></a>二叉树的遍历</h3><h4 id="前序遍历"><a href="#前序遍历" class="headerlink" title="前序遍历"></a>前序遍历</h4><p><strong>先遍历父节点</strong>，再遍历左子节点，最后遍历右子节点</p>
<h4 id="中序遍历"><a href="#中序遍历" class="headerlink" title="中序遍历"></a>中序遍历</h4><p>先遍历左子节点，<strong>再遍历父节点</strong>，最后遍历右子节点</p>
<h4 id="后序遍历"><a href="#后序遍历" class="headerlink" title="后序遍历"></a>后序遍历</h4><p>先遍历左子节点，再遍历右子节点，最后<strong>遍历父节点</strong></p>
<p><strong>可以看出，前中后的区别在于父节点遍历的时机</strong></p>
<h4 id="示意图"><a href="#示意图" class="headerlink" title="示意图"></a>示意图</h4><p><img src="https://nyimapicture.oss-cn-beijing.aliyuncs.com/img/20200725144409.png" srcset="/img/loading.gif" alt=""></p>
<p><strong>前序遍历结果</strong>：1、2、5、6、3</p>
<p><strong>中序遍历结果</strong>：5、2、6、1、3</p>
<p><strong>后序遍历结果</strong>：5、6、2、3、1</p>
<h4 id="实际代码"><a href="#实际代码" class="headerlink" title="实际代码"></a>实际代码</h4><p>此代码使用<strong>手动</strong>的方式创建二叉树，使用<strong>递归</strong>的方式遍历二叉树</p>
<pre><code class="hljs java"><span class="hljs-keyword">public</span> <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">Demo1</span> </span>&#123;
   <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">static</span> <span class="hljs-keyword">void</span> <span class="hljs-title">main</span><span class="hljs-params">(String[] args)</span> </span>&#123;
      <span class="hljs-comment">//创建二叉树</span>
      BinaryTree binaryTree = <span class="hljs-keyword">new</span> BinaryTree();

      <span class="hljs-comment">//手动创建节点，并放入二叉树中</span>
      StuNode stu1 = <span class="hljs-keyword">new</span> StuNode(<span class="hljs-number">1</span>, <span class="hljs-string">"A"</span>);
      StuNode stu2 = <span class="hljs-keyword">new</span> StuNode(<span class="hljs-number">2</span>, <span class="hljs-string">"B"</span>);
      StuNode stu3 = <span class="hljs-keyword">new</span> StuNode(<span class="hljs-number">3</span>, <span class="hljs-string">"C"</span>);
      StuNode stu4 = <span class="hljs-keyword">new</span> StuNode(<span class="hljs-number">4</span>, <span class="hljs-string">"D"</span>);
      stu1.setLeft(stu2);
      stu1.setRight(stu3);
      stu3.setRight(stu4);
      binaryTree.setRoot(stu1);

      <span class="hljs-comment">//遍历二叉树</span>
      binaryTree.preTraverse();
      binaryTree.midTraverse();
      binaryTree.lastTraverse();
   &#125;
&#125;

<span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">BinaryTree</span> </span>&#123;
   <span class="hljs-comment">/**</span>
<span class="hljs-comment">    * 根节点</span>
<span class="hljs-comment">    */</span>
   <span class="hljs-keyword">private</span> StuNode root;

   <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">setRoot</span><span class="hljs-params">(StuNode root)</span> </span>&#123;
      <span class="hljs-keyword">this</span>.root = root;
   &#125;

   <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">preTraverse</span><span class="hljs-params">()</span> </span>&#123;
      <span class="hljs-keyword">if</span>(root != <span class="hljs-keyword">null</span>) &#123;
         System.out.println(<span class="hljs-string">"前序遍历"</span>);
         root.preTraverse();
         System.out.println();
      &#125;<span class="hljs-keyword">else</span> &#123;
         System.out.println(<span class="hljs-string">"二叉树为空！"</span>);
      &#125;
   &#125;

   <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">midTraverse</span><span class="hljs-params">()</span> </span>&#123;
      <span class="hljs-keyword">if</span>(root != <span class="hljs-keyword">null</span>) &#123;
         System.out.println(<span class="hljs-string">"中序遍历"</span>);
         root.midTraverse();
         System.out.println();
      &#125;<span class="hljs-keyword">else</span> &#123;
         System.out.println(<span class="hljs-string">"二叉树为空！"</span>);
      &#125;  &#125;

   <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">lastTraverse</span><span class="hljs-params">()</span> </span>&#123;
      <span class="hljs-keyword">if</span>(root != <span class="hljs-keyword">null</span>) &#123;
         System.out.println(<span class="hljs-string">"后序遍历"</span>);
         root.lastTraverse();
         System.out.println();
      &#125;<span class="hljs-keyword">else</span> &#123;
         System.out.println(<span class="hljs-string">"二叉树为空！"</span>);
      &#125;  &#125;
&#125;

<span class="hljs-comment">/**</span>
<span class="hljs-comment"> * 二叉树中的一个节点</span>
<span class="hljs-comment"> * 保存了学生信息和左右孩子信息</span>
<span class="hljs-comment"> */</span>
<span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">StuNode</span> </span>&#123;
   <span class="hljs-keyword">int</span> id;
   String name;
   StuNode left;
   StuNode right;

   <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-title">StuNode</span><span class="hljs-params">(<span class="hljs-keyword">int</span> id, String name)</span> </span>&#123;
      <span class="hljs-keyword">this</span>.id = id;
      <span class="hljs-keyword">this</span>.name = name;
   &#125;

   <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">int</span> <span class="hljs-title">getId</span><span class="hljs-params">()</span> </span>&#123;
      <span class="hljs-keyword">return</span> id;
   &#125;

   <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">setId</span><span class="hljs-params">(<span class="hljs-keyword">int</span> id)</span> </span>&#123;
      <span class="hljs-keyword">this</span>.id = id;
   &#125;

   <span class="hljs-function"><span class="hljs-keyword">public</span> String <span class="hljs-title">getName</span><span class="hljs-params">()</span> </span>&#123;
      <span class="hljs-keyword">return</span> name;
   &#125;

   <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">setName</span><span class="hljs-params">(String name)</span> </span>&#123;
      <span class="hljs-keyword">this</span>.name = name;
   &#125;

   <span class="hljs-function"><span class="hljs-keyword">public</span> StuNode <span class="hljs-title">getLeft</span><span class="hljs-params">()</span> </span>&#123;
      <span class="hljs-keyword">return</span> left;
   &#125;

   <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">setLeft</span><span class="hljs-params">(StuNode left)</span> </span>&#123;
      <span class="hljs-keyword">this</span>.left = left;
   &#125;

   <span class="hljs-function"><span class="hljs-keyword">public</span> StuNode <span class="hljs-title">getRight</span><span class="hljs-params">()</span> </span>&#123;
      <span class="hljs-keyword">return</span> right;
   &#125;

   <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">setRight</span><span class="hljs-params">(StuNode right)</span> </span>&#123;
      <span class="hljs-keyword">this</span>.right = right;
   &#125;

   <span class="hljs-meta">@Override</span>
   <span class="hljs-function"><span class="hljs-keyword">public</span> String <span class="hljs-title">toString</span><span class="hljs-params">()</span> </span>&#123;
      <span class="hljs-keyword">return</span> <span class="hljs-string">"StuNode&#123;"</span> +
            <span class="hljs-string">"id="</span> + id +
            <span class="hljs-string">", name='"</span> + name + <span class="hljs-string">'\''</span> +
            <span class="hljs-string">'&#125;'</span>;
   &#125;

   <span class="hljs-comment">/**</span>
<span class="hljs-comment">    * 前序遍历</span>
<span class="hljs-comment">    */</span>
   <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">preTraverse</span><span class="hljs-params">()</span> </span>&#123;
      <span class="hljs-comment">//父节点的位置</span>
      System.out.println(<span class="hljs-keyword">this</span>);
      <span class="hljs-keyword">if</span>(left != <span class="hljs-keyword">null</span>) &#123;
         left.preTraverse();
      &#125;
      <span class="hljs-keyword">if</span>(right != <span class="hljs-keyword">null</span>) &#123;
         right.preTraverse();
      &#125;
   &#125;

   <span class="hljs-comment">/**</span>
<span class="hljs-comment">    * 中序遍历</span>
<span class="hljs-comment">    */</span>
   <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">midTraverse</span><span class="hljs-params">()</span> </span>&#123;
      <span class="hljs-keyword">if</span>(left != <span class="hljs-keyword">null</span>) &#123;
         left.midTraverse();
      &#125;
      <span class="hljs-comment">//父节点的位置</span>
      System.out.println(<span class="hljs-keyword">this</span>);
      <span class="hljs-keyword">if</span>(right != <span class="hljs-keyword">null</span>) &#123;
         right.midTraverse();
      &#125;
   &#125;

   <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">lastTraverse</span><span class="hljs-params">()</span> </span>&#123;
      <span class="hljs-keyword">if</span>(left != <span class="hljs-keyword">null</span>) &#123;
         left.lastTraverse();
      &#125;
      <span class="hljs-keyword">if</span>(right != <span class="hljs-keyword">null</span>) &#123;
         right.lastTraverse();
      &#125;
      <span class="hljs-comment">//父节点的位置</span>
      System.out.println(<span class="hljs-keyword">this</span>);
   &#125;
&#125;</code></pre>

<p><strong>运行结果</strong></p>
<pre><code class="hljs routeros">前序遍历
StuNode&#123;<span class="hljs-attribute">id</span>=1, <span class="hljs-attribute">name</span>=<span class="hljs-string">'A'</span>&#125;
StuNode&#123;<span class="hljs-attribute">id</span>=2, <span class="hljs-attribute">name</span>=<span class="hljs-string">'B'</span>&#125;
StuNode&#123;<span class="hljs-attribute">id</span>=3, <span class="hljs-attribute">name</span>=<span class="hljs-string">'C'</span>&#125;
StuNode&#123;<span class="hljs-attribute">id</span>=4, <span class="hljs-attribute">name</span>=<span class="hljs-string">'D'</span>&#125;

中序遍历
StuNode&#123;<span class="hljs-attribute">id</span>=2, <span class="hljs-attribute">name</span>=<span class="hljs-string">'B'</span>&#125;
StuNode&#123;<span class="hljs-attribute">id</span>=1, <span class="hljs-attribute">name</span>=<span class="hljs-string">'A'</span>&#125;
StuNode&#123;<span class="hljs-attribute">id</span>=3, <span class="hljs-attribute">name</span>=<span class="hljs-string">'C'</span>&#125;
StuNode&#123;<span class="hljs-attribute">id</span>=4, <span class="hljs-attribute">name</span>=<span class="hljs-string">'D'</span>&#125;

后序遍历
StuNode&#123;<span class="hljs-attribute">id</span>=2, <span class="hljs-attribute">name</span>=<span class="hljs-string">'B'</span>&#125;
StuNode&#123;<span class="hljs-attribute">id</span>=4, <span class="hljs-attribute">name</span>=<span class="hljs-string">'D'</span>&#125;
StuNode&#123;<span class="hljs-attribute">id</span>=3, <span class="hljs-attribute">name</span>=<span class="hljs-string">'C'</span>&#125;
StuNode&#123;<span class="hljs-attribute">id</span>=1, <span class="hljs-attribute">name</span>=<span class="hljs-string">'A'</span>&#125;</code></pre>



<h4 id="迭代实现"><a href="#迭代实现" class="headerlink" title="迭代实现"></a>迭代实现</h4><p>使用迭代对二叉树进行遍历与递归类似，不过需要自己维护一个<strong>栈</strong>用于存放节点</p>
<pre><code class="hljs java"><span class="hljs-keyword">public</span> <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">Demo5</span> </span>&#123;
   <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">static</span> <span class="hljs-keyword">void</span> <span class="hljs-title">main</span><span class="hljs-params">(String[] args)</span> </span>&#123;
      TreeNode node1 = <span class="hljs-keyword">new</span> TreeNode(<span class="hljs-number">1</span>);
      TreeNode node2 = <span class="hljs-keyword">new</span> TreeNode(<span class="hljs-number">2</span>);
      TreeNode node3 = <span class="hljs-keyword">new</span> TreeNode(<span class="hljs-number">3</span>);

      node1.left = node2;
      node1.right = node3;

      List&lt;Integer&gt; integers = preTraverse(node1);
      System.out.println(<span class="hljs-string">"前序遍历结果"</span>);
      <span class="hljs-keyword">for</span> (Integer integer : integers) &#123;
         System.out.print(integer);
         System.out.print(<span class="hljs-string">" "</span>);
      &#125;
      System.out.println();

      List&lt;Integer&gt; integers2 = midTraverse(node1);
      System.out.println(<span class="hljs-string">"中遍历结果"</span>);
      <span class="hljs-keyword">for</span> (Integer integer : integers2) &#123;
         System.out.print(integer);
         System.out.print(<span class="hljs-string">" "</span>);
      &#125;
      System.out.println();

      List&lt;Integer&gt; integers3 = lastTraverse(node1);
      System.out.println(<span class="hljs-string">"后遍历结果"</span>);
      <span class="hljs-keyword">for</span> (Integer integer : integers3) &#123;
         System.out.print(integer);
         System.out.print(<span class="hljs-string">" "</span>);
      &#125;
      System.out.println();
   &#125;

   <span class="hljs-comment">/**</span>
<span class="hljs-comment">    * 使用迭代法对二叉树进行前序遍历</span>
<span class="hljs-comment">    * <span class="hljs-doctag">@param</span> root 二叉树根节点</span>
<span class="hljs-comment">    * <span class="hljs-doctag">@return</span> 遍历后的集合</span>
<span class="hljs-comment">    */</span>
   <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">static</span> List&lt;Integer&gt; <span class="hljs-title">preTraverse</span><span class="hljs-params">(TreeNode root)</span> </span>&#123;
      <span class="hljs-comment">// 用于存放结果的集合</span>
      List&lt;Integer&gt; result = <span class="hljs-keyword">new</span> ArrayList&lt;&gt;();

      <span class="hljs-keyword">if</span> (root == <span class="hljs-keyword">null</span>) &#123;
         <span class="hljs-keyword">return</span> result;
      &#125;

      <span class="hljs-comment">// 栈，用于存放遍历的节点</span>
      Stack&lt;TreeNode&gt; stack = <span class="hljs-keyword">new</span> Stack&lt;&gt;();
      stack.push(root);
      <span class="hljs-comment">// 遍历二叉树</span>
      <span class="hljs-keyword">while</span> (!stack.isEmpty()) &#123;
         <span class="hljs-comment">// 栈顶元素出栈，并放入集合中</span>
         root = stack.pop();
         result.add(root.val);
         <span class="hljs-comment">// 先遍历右子树，将其压栈</span>
         <span class="hljs-keyword">if</span> (root.right != <span class="hljs-keyword">null</span>) &#123;
            stack.push(root.right);
         &#125;
         <span class="hljs-comment">// 遍历左子树,压栈</span>
         <span class="hljs-keyword">if</span> (root.left != <span class="hljs-keyword">null</span>) &#123;
            stack.push(root.left);
         &#125;
      &#125;
      <span class="hljs-keyword">return</span> result;
   &#125;

   <span class="hljs-comment">/**</span>
<span class="hljs-comment">    * 使用迭代法对二叉树进行中序遍历</span>
<span class="hljs-comment">    * <span class="hljs-doctag">@param</span> root 二叉树根节点</span>
<span class="hljs-comment">    * <span class="hljs-doctag">@return</span> 中序遍历结果集合</span>
<span class="hljs-comment">    */</span>
   <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">static</span> List&lt;Integer&gt; <span class="hljs-title">midTraverse</span><span class="hljs-params">(TreeNode root)</span> </span>&#123;
      List&lt;Integer&gt; result = <span class="hljs-keyword">new</span> ArrayList&lt;&gt;();

      <span class="hljs-keyword">if</span> (root == <span class="hljs-keyword">null</span>) &#123;
         <span class="hljs-keyword">return</span> result;
      &#125;

      Stack&lt;TreeNode&gt; stack = <span class="hljs-keyword">new</span> Stack&lt;&gt;();

      <span class="hljs-keyword">while</span> (root != <span class="hljs-keyword">null</span> || !stack.isEmpty()) &#123;
         <span class="hljs-comment">// 节点压栈，并遍历其左子树</span>
         <span class="hljs-keyword">while</span> (root != <span class="hljs-keyword">null</span>) &#123;
            stack.push(root);
            root = root.left;
         &#125;

         <span class="hljs-comment">// 栈顶元素出栈，放入结果集合</span>
         root = stack.pop();
         result.add(root.val);

         <span class="hljs-comment">// 遍历该节点的右子树</span>
         root = root.right;
      &#125;
      <span class="hljs-keyword">return</span> result;
   &#125;

   <span class="hljs-comment">/**</span>
<span class="hljs-comment">    * 使用迭代法的后序遍历</span>
<span class="hljs-comment">    * <span class="hljs-doctag">@param</span> root 二叉树根节点</span>
<span class="hljs-comment">    * <span class="hljs-doctag">@return</span> 后序遍历集合</span>
<span class="hljs-comment">    */</span>
   <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">static</span> List&lt;Integer&gt; <span class="hljs-title">lastTraverse</span><span class="hljs-params">(TreeNode root)</span> </span>&#123;
      List&lt;Integer&gt; result = <span class="hljs-keyword">new</span> ArrayList&lt;&gt;();

      <span class="hljs-keyword">if</span> (root == <span class="hljs-keyword">null</span>) &#123;
         <span class="hljs-keyword">return</span> result;
      &#125;

      Stack&lt;TreeNode&gt; stack = <span class="hljs-keyword">new</span> Stack&lt;&gt;();
      <span class="hljs-comment">// 保存放入集合的右子树，避免重复放入</span>
      TreeNode pre = <span class="hljs-keyword">null</span>;

      <span class="hljs-keyword">while</span> (root != <span class="hljs-keyword">null</span> || !stack.isEmpty()) &#123;
         <span class="hljs-keyword">while</span> (root != <span class="hljs-keyword">null</span>) &#123;
            stack.push(root);
            root = root.left;
         &#125;

         <span class="hljs-comment">// 获取栈顶元素</span>
         root = stack.pop();

         <span class="hljs-comment">// 如果该元素没有右子树，或者右子树已近被遍历过了，就放入集合</span>
         <span class="hljs-keyword">if</span> (root.right == <span class="hljs-keyword">null</span> || root.right == pre) &#123;
            result.add(root.val);
            pre = root;
            root = <span class="hljs-keyword">null</span>;
         &#125; <span class="hljs-keyword">else</span> &#123;
            <span class="hljs-comment">// 否则就继续遍历该节点的右子树</span>
            stack.push(root);
            root = root.right;
         &#125;
      &#125;
      <span class="hljs-keyword">return</span> result;
   &#125;
&#125;</code></pre>

<p><strong>运行结果</strong></p>
<pre><code class="hljs java">前序遍历结果
<span class="hljs-number">1</span> <span class="hljs-number">2</span> <span class="hljs-number">3</span> 
    
中遍历结果
<span class="hljs-number">2</span> <span class="hljs-number">1</span> <span class="hljs-number">3</span> 
    
后遍历结果
<span class="hljs-number">2</span> <span class="hljs-number">3</span> <span class="hljs-number">1</span></code></pre>



<h3 id="二叉树的查找"><a href="#二叉树的查找" class="headerlink" title="二叉树的查找"></a>二叉树的查找</h3><p>前、中、后序查找的思路与遍历相似，当找到对应的元素时，直接返回即可。</p>
<h4 id="实现代码"><a href="#实现代码" class="headerlink" title="实现代码"></a>实现代码</h4><pre><code class="hljs java"><span class="hljs-keyword">public</span> <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">Demo2</span> </span>&#123;
   <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">static</span> <span class="hljs-keyword">void</span> <span class="hljs-title">main</span><span class="hljs-params">(String[] args)</span> </span>&#123;
      <span class="hljs-comment">//创建根节点</span>
      BinarySearchTree tree = <span class="hljs-keyword">new</span> BinarySearchTree();

      <span class="hljs-comment">//手动创建节点</span>
      Student student1 = <span class="hljs-keyword">new</span> Student(<span class="hljs-number">1</span>, <span class="hljs-string">"A"</span>);
      Student student2 = <span class="hljs-keyword">new</span> Student(<span class="hljs-number">2</span>, <span class="hljs-string">"B"</span>);
      Student student3 = <span class="hljs-keyword">new</span> Student(<span class="hljs-number">3</span>, <span class="hljs-string">"C"</span>);
      Student student4 = <span class="hljs-keyword">new</span> Student(<span class="hljs-number">4</span>, <span class="hljs-string">"D"</span>);
      Student student5 = <span class="hljs-keyword">new</span> Student(<span class="hljs-number">5</span>, <span class="hljs-string">"E"</span>);
      student1.setLeft(student2);
      student1.setRight(student3);
      student2.setLeft(student4);
      student3.setRight(student5);

      <span class="hljs-comment">//指定根节点</span>
      tree.setRoot(student1);

      <span class="hljs-comment">//查找</span>
      tree.preSearch(<span class="hljs-number">3</span>);
      tree.midSearch(<span class="hljs-number">4</span>);
      tree.lastSearch(<span class="hljs-number">7</span>);

   &#125;
&#125;

<span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">BinarySearchTree</span> </span>&#123;
   <span class="hljs-keyword">private</span> Student root;

   <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">setRoot</span><span class="hljs-params">(Student root)</span> </span>&#123;
      <span class="hljs-keyword">this</span>.root = root;
   &#125;

   <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">preSearch</span><span class="hljs-params">(<span class="hljs-keyword">int</span> id)</span> </span>&#123;
      System.out.println(<span class="hljs-string">"前序查找"</span>);
      <span class="hljs-keyword">if</span>(root == <span class="hljs-keyword">null</span>) &#123;
         System.out.println(<span class="hljs-string">"树为空！"</span>);
         <span class="hljs-keyword">return</span>;
      &#125;
      Student result = root.preSearch(id);
      <span class="hljs-keyword">if</span>(result == <span class="hljs-keyword">null</span>) &#123;
         System.out.println(<span class="hljs-string">"未找到该元素"</span>);
         System.out.println();
         <span class="hljs-keyword">return</span>;
      &#125;
      System.out.println(result);
      System.out.println();
   &#125;

   <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">midSearch</span><span class="hljs-params">(<span class="hljs-keyword">int</span> id)</span> </span>&#123;
      System.out.println(<span class="hljs-string">"中序查找"</span>);
      <span class="hljs-keyword">if</span>(root == <span class="hljs-keyword">null</span>) &#123;
         System.out.println(<span class="hljs-string">"树为空！"</span>);
         <span class="hljs-keyword">return</span>;
      &#125;
      Student result = root.midSearch(id);
      <span class="hljs-keyword">if</span>(result == <span class="hljs-keyword">null</span>) &#123;
         System.out.println(<span class="hljs-string">"未找到该元素"</span>);
         System.out.println();
         <span class="hljs-keyword">return</span>;
      &#125;
      System.out.println(result);
      System.out.println();
   &#125;

   <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">lastSearch</span><span class="hljs-params">(<span class="hljs-keyword">int</span> id)</span> </span>&#123;
      System.out.println(<span class="hljs-string">"后序查找"</span>);
      <span class="hljs-keyword">if</span>(root == <span class="hljs-keyword">null</span>) &#123;
         System.out.println(<span class="hljs-string">"树为空！"</span>);
         <span class="hljs-keyword">return</span>;
      &#125;
      Student result = root.lastSearch(id);
      <span class="hljs-keyword">if</span>(result == <span class="hljs-keyword">null</span>) &#123;
         System.out.println(<span class="hljs-string">"未找到该元素"</span>);
         System.out.println();
         <span class="hljs-keyword">return</span>;
      &#125;
      System.out.println(result);
      System.out.println();
   &#125;
&#125;

<span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">Student</span> </span>&#123;
   <span class="hljs-keyword">int</span> id;
   String name;
   Student left;
   Student right;

   <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-title">Student</span><span class="hljs-params">(<span class="hljs-keyword">int</span> id, String name)</span> </span>&#123;
      <span class="hljs-keyword">this</span>.id = id;
      <span class="hljs-keyword">this</span>.name = name;
   &#125;

   <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">int</span> <span class="hljs-title">getId</span><span class="hljs-params">()</span> </span>&#123;
      <span class="hljs-keyword">return</span> id;
   &#125;

   <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">setId</span><span class="hljs-params">(<span class="hljs-keyword">int</span> id)</span> </span>&#123;
      <span class="hljs-keyword">this</span>.id = id;
   &#125;

   <span class="hljs-function"><span class="hljs-keyword">public</span> String <span class="hljs-title">getName</span><span class="hljs-params">()</span> </span>&#123;
      <span class="hljs-keyword">return</span> name;
   &#125;

   <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">setName</span><span class="hljs-params">(String name)</span> </span>&#123;
      <span class="hljs-keyword">this</span>.name = name;
   &#125;

   <span class="hljs-function"><span class="hljs-keyword">public</span> Student <span class="hljs-title">getLeft</span><span class="hljs-params">()</span> </span>&#123;
      <span class="hljs-keyword">return</span> left;
   &#125;

   <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">setLeft</span><span class="hljs-params">(Student left)</span> </span>&#123;
      <span class="hljs-keyword">this</span>.left = left;
   &#125;

   <span class="hljs-function"><span class="hljs-keyword">public</span> Student <span class="hljs-title">getRight</span><span class="hljs-params">()</span> </span>&#123;
      <span class="hljs-keyword">return</span> right;
   &#125;

   <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">setRight</span><span class="hljs-params">(Student right)</span> </span>&#123;
      <span class="hljs-keyword">this</span>.right = right;
   &#125;

   <span class="hljs-meta">@Override</span>
   <span class="hljs-function"><span class="hljs-keyword">public</span> String <span class="hljs-title">toString</span><span class="hljs-params">()</span> </span>&#123;
      <span class="hljs-keyword">return</span> <span class="hljs-string">"Student&#123;"</span> +
            <span class="hljs-string">"id="</span> + id +
            <span class="hljs-string">", name='"</span> + name + <span class="hljs-string">'\''</span> +
            <span class="hljs-string">'&#125;'</span>;
   &#125;

   <span class="hljs-comment">/**</span>
<span class="hljs-comment">    * 前序查找</span>
<span class="hljs-comment">    * <span class="hljs-doctag">@param</span> id 要查找的学生id</span>
<span class="hljs-comment">    * <span class="hljs-doctag">@return</span> 查找到的学生</span>
<span class="hljs-comment">    */</span>
   <span class="hljs-function"><span class="hljs-keyword">public</span> Student <span class="hljs-title">preSearch</span><span class="hljs-params">(<span class="hljs-keyword">int</span> id)</span> </span>&#123;
      <span class="hljs-comment">//如果找到了，就返回</span>
      <span class="hljs-keyword">if</span>(<span class="hljs-keyword">this</span>.id == id) &#123;
         <span class="hljs-keyword">return</span> <span class="hljs-keyword">this</span>;
      &#125;

      <span class="hljs-comment">//在左子树中查找，如果找到了就返回</span>
      Student student = <span class="hljs-keyword">null</span>;
      <span class="hljs-keyword">if</span>(left != <span class="hljs-keyword">null</span>) &#123;
         student = left.preSearch(id);
      &#125;
      <span class="hljs-keyword">if</span>(student != <span class="hljs-keyword">null</span>) &#123;
         <span class="hljs-keyword">return</span> student;
      &#125;

      <span class="hljs-comment">//在右子树中查找，无论是否找到，都需要返回</span>
      <span class="hljs-keyword">if</span>(right != <span class="hljs-keyword">null</span>) &#123;
         student = right.preSearch(id);
      &#125;
      <span class="hljs-keyword">return</span> student;
   &#125;

   <span class="hljs-comment">/**</span>
<span class="hljs-comment">    * 中序查找</span>
<span class="hljs-comment">    * <span class="hljs-doctag">@param</span> id 要查找的学生id</span>
<span class="hljs-comment">    * <span class="hljs-doctag">@return</span> 查找到的学生</span>
<span class="hljs-comment">    */</span>
   <span class="hljs-function"><span class="hljs-keyword">public</span> Student <span class="hljs-title">midSearch</span><span class="hljs-params">(<span class="hljs-keyword">int</span> id)</span> </span>&#123;
      Student student = <span class="hljs-keyword">null</span>;
      <span class="hljs-keyword">if</span>(left != <span class="hljs-keyword">null</span>) &#123;
         student = left.midSearch(id);
      &#125;
      <span class="hljs-keyword">if</span>(student != <span class="hljs-keyword">null</span>) &#123;
         <span class="hljs-keyword">return</span> student;
      &#125;

      <span class="hljs-comment">//找到了就返回</span>
      <span class="hljs-keyword">if</span>(<span class="hljs-keyword">this</span>.id == id) &#123;
         <span class="hljs-keyword">return</span> <span class="hljs-keyword">this</span>;
      &#125;

      <span class="hljs-keyword">if</span>(right != <span class="hljs-keyword">null</span>) &#123;
         student = right.midSearch(id);
      &#125;
      <span class="hljs-keyword">return</span> student;
   &#125;

   <span class="hljs-comment">/**</span>
<span class="hljs-comment">    * 后序查找</span>
<span class="hljs-comment">    * <span class="hljs-doctag">@param</span> id 要查找的学生id</span>
<span class="hljs-comment">    * <span class="hljs-doctag">@return</span> 查找到的学生</span>
<span class="hljs-comment">    */</span>
   <span class="hljs-function"><span class="hljs-keyword">public</span> Student <span class="hljs-title">lastSearch</span><span class="hljs-params">(<span class="hljs-keyword">int</span> id)</span> </span>&#123;
      Student student = <span class="hljs-keyword">null</span>;
      <span class="hljs-keyword">if</span>(left != <span class="hljs-keyword">null</span>) &#123;
         student = left.lastSearch(id);
      &#125;
      <span class="hljs-keyword">if</span>(student !=<span class="hljs-keyword">null</span>) &#123;
         <span class="hljs-keyword">return</span> student;
      &#125;

      <span class="hljs-keyword">if</span>(right != <span class="hljs-keyword">null</span>) &#123;
         student = right.lastSearch(id);
      &#125;

      <span class="hljs-keyword">if</span>(<span class="hljs-keyword">this</span>.id == id) &#123;
         <span class="hljs-keyword">return</span> <span class="hljs-keyword">this</span>;
      &#125;

      <span class="hljs-keyword">return</span> student;
   &#125;
&#125;</code></pre>



<p><strong>运行结果</strong></p>
<pre><code class="hljs routeros">前序查找
Student&#123;<span class="hljs-attribute">id</span>=3, <span class="hljs-attribute">name</span>=<span class="hljs-string">'C'</span>&#125;

中序查找
Student&#123;<span class="hljs-attribute">id</span>=4, <span class="hljs-attribute">name</span>=<span class="hljs-string">'D'</span>&#125;

后序查找
未找到该元素</code></pre>



<h3 id="二叉树的删除"><a href="#二叉树的删除" class="headerlink" title="二叉树的删除"></a>二叉树的删除</h3><h4 id="删除要求"><a href="#删除要求" class="headerlink" title="删除要求"></a>删除要求</h4><ul>
<li>如果删除的是叶子节点，则直接删除即可</li>
<li>如果删除的是非叶子节点，则<strong>删除该子树</strong></li>
</ul>
<h4 id="删除思路"><a href="#删除思路" class="headerlink" title="删除思路"></a>删除思路</h4><ul>
<li><p>因为我们的二叉树是<strong>单向的</strong>，所以我们是判断<strong>当前结点的子结点</strong>是否需要删除结点，而不能去判断当前这个结点是不是需要删除结点</p>
</li>
<li><p>如果当前结点的<strong>左子结点不为空</strong>，并且左子结点就是要删除结点，就将 <strong>this.left = null</strong>; 并且就返回 (结束递归删除)</p>
</li>
<li><p>如果当前结点的<strong>右子结点不为空</strong>，并且右子结点就是要删除结点，就将 <strong>this.right= null</strong> ;并且就返回 (结束递归删除)</p>
</li>
<li><p>如果第2和第3步没有删除结点，那么我们就需要向左子树进行递归删除</p>
</li>
<li><p>如果 4步也没有删除结点，则应当向右子树进行递归删除</p>
</li>
</ul>
<h4 id="实现代码-1"><a href="#实现代码-1" class="headerlink" title="实现代码"></a>实现代码</h4><pre><code class="hljs java"><span class="hljs-keyword">public</span> <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">Demo3</span> </span>&#123;
   <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">static</span> <span class="hljs-keyword">void</span> <span class="hljs-title">main</span><span class="hljs-params">(String[] args)</span> </span>&#123;
      <span class="hljs-comment">//创建根节点</span>
      BinaryDeleteTree deleteTree = <span class="hljs-keyword">new</span> BinaryDeleteTree();

      <span class="hljs-comment">//手动创建节点</span>
      StudentNode student1 = <span class="hljs-keyword">new</span> StudentNode(<span class="hljs-number">1</span>, <span class="hljs-string">"A"</span>);
      StudentNode student2 = <span class="hljs-keyword">new</span> StudentNode(<span class="hljs-number">2</span>, <span class="hljs-string">"B"</span>);
      StudentNode student3 = <span class="hljs-keyword">new</span> StudentNode(<span class="hljs-number">3</span>, <span class="hljs-string">"C"</span>);
      StudentNode student4 = <span class="hljs-keyword">new</span> StudentNode(<span class="hljs-number">4</span>, <span class="hljs-string">"D"</span>);
      StudentNode student5 = <span class="hljs-keyword">new</span> StudentNode(<span class="hljs-number">5</span>, <span class="hljs-string">"E"</span>);
      student1.setLeft(student2);
      student1.setRight(student3);
      student2.setLeft(student4);
      student3.setRight(student5);

      <span class="hljs-comment">//指定根节点</span>
      deleteTree.setRoot(student1);

      <span class="hljs-comment">//删除节点</span>
      deleteTree.deleteNode(<span class="hljs-number">3</span>);
   &#125;
&#125;


<span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">BinaryDeleteTree</span> </span>&#123;
   StudentNode root;

   <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">setRoot</span><span class="hljs-params">(StudentNode root)</span> </span>&#123;
      <span class="hljs-keyword">this</span>.root = root;
   &#125;

   <span class="hljs-comment">/**</span>
<span class="hljs-comment">    * 删除节点</span>
<span class="hljs-comment">    * <span class="hljs-doctag">@param</span> id 删除节点的id</span>
<span class="hljs-comment">    */</span>
   <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">deleteNode</span><span class="hljs-params">(<span class="hljs-keyword">int</span> id)</span> </span>&#123;
      System.out.println(<span class="hljs-string">"删除节点"</span>);
      <span class="hljs-keyword">if</span>(root.id == id) &#123;
         root = <span class="hljs-keyword">null</span>;
         System.out.println(<span class="hljs-string">"根节点被删除"</span>);
         <span class="hljs-keyword">return</span>;
      &#125;
      <span class="hljs-comment">//调用删除方法</span>
      root.deleteNode(id);
   &#125;
&#125;

<span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">StudentNode</span> </span>&#123;
   <span class="hljs-keyword">int</span> id;
   String name;
   StudentNode left;
   StudentNode right;

   <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-title">StudentNode</span><span class="hljs-params">(<span class="hljs-keyword">int</span> id, String name)</span> </span>&#123;
      <span class="hljs-keyword">this</span>.id = id;
      <span class="hljs-keyword">this</span>.name = name;
   &#125;

   <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">int</span> <span class="hljs-title">getId</span><span class="hljs-params">()</span> </span>&#123;
      <span class="hljs-keyword">return</span> id;
   &#125;

   <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">setId</span><span class="hljs-params">(<span class="hljs-keyword">int</span> id)</span> </span>&#123;
      <span class="hljs-keyword">this</span>.id = id;
   &#125;

   <span class="hljs-function"><span class="hljs-keyword">public</span> String <span class="hljs-title">getName</span><span class="hljs-params">()</span> </span>&#123;
      <span class="hljs-keyword">return</span> name;
   &#125;

   <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">setName</span><span class="hljs-params">(String name)</span> </span>&#123;
      <span class="hljs-keyword">this</span>.name = name;
   &#125;

   <span class="hljs-function"><span class="hljs-keyword">public</span> StudentNode <span class="hljs-title">getLeft</span><span class="hljs-params">()</span> </span>&#123;
      <span class="hljs-keyword">return</span> left;
   &#125;

   <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">setLeft</span><span class="hljs-params">(StudentNode left)</span> </span>&#123;
      <span class="hljs-keyword">this</span>.left = left;
   &#125;

   <span class="hljs-function"><span class="hljs-keyword">public</span> StudentNode <span class="hljs-title">getRight</span><span class="hljs-params">()</span> </span>&#123;
      <span class="hljs-keyword">return</span> right;
   &#125;

   <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">setRight</span><span class="hljs-params">(StudentNode right)</span> </span>&#123;
      <span class="hljs-keyword">this</span>.right = right;
   &#125;

   <span class="hljs-meta">@Override</span>
   <span class="hljs-function"><span class="hljs-keyword">public</span> String <span class="hljs-title">toString</span><span class="hljs-params">()</span> </span>&#123;
      <span class="hljs-keyword">return</span> <span class="hljs-string">"StudentNode&#123;"</span> +
            <span class="hljs-string">"id="</span> + id +
            <span class="hljs-string">", name='"</span> + name + <span class="hljs-string">'\''</span> +
            <span class="hljs-string">'&#125;'</span>;
   &#125;

   <span class="hljs-comment">/**</span>
<span class="hljs-comment">    * 删除节点</span>
<span class="hljs-comment">    * <span class="hljs-doctag">@param</span> id 删除节点的id</span>
<span class="hljs-comment">    */</span>
   <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">deleteNode</span><span class="hljs-params">(<span class="hljs-keyword">int</span> id)</span> </span>&#123;
      <span class="hljs-comment">//如果左子树不为空且是要查找的节点，就删除</span>
      <span class="hljs-keyword">if</span>(left != <span class="hljs-keyword">null</span> &amp;&amp; left.id == id) &#123;
         left = <span class="hljs-keyword">null</span>;
         System.out.println(<span class="hljs-string">"删除成功"</span>);
         <span class="hljs-keyword">return</span>;
      &#125;

      <span class="hljs-comment">//如果右子树不为空且是要查找的节点，就删除</span>
      <span class="hljs-keyword">if</span>(right != <span class="hljs-keyword">null</span> &amp;&amp; right.id == id) &#123;
         right = <span class="hljs-keyword">null</span>;
         System.out.println(<span class="hljs-string">"删除成功"</span>);
         <span class="hljs-keyword">return</span>;
      &#125;

      <span class="hljs-comment">//左递归，继续查找</span>
      <span class="hljs-keyword">if</span>(left != <span class="hljs-keyword">null</span>) &#123;
         left.deleteNode(id);
      &#125;

      <span class="hljs-comment">//右递归，继续查找</span>
      <span class="hljs-keyword">if</span>(right != <span class="hljs-keyword">null</span>) &#123;
         right.deleteNode(id);
      &#125;
   &#125;
&#125;</code></pre>



<h3 id="顺序存储二叉树"><a href="#顺序存储二叉树" class="headerlink" title="顺序存储二叉树"></a>顺序存储二叉树</h3><h4 id="基本说明"><a href="#基本说明" class="headerlink" title="基本说明"></a><strong>基本说明</strong></h4><p>从数据存储来看，数组存储方式和树的存储方式可以相互转换，即<strong>数组可以转换成树</strong>，<strong>树也可以转换成数组</strong></p>
<p><img src="https://nyimapicture.oss-cn-beijing.aliyuncs.com/img/20200726130159.png" srcset="/img/loading.gif" alt=""></p>
<h4 id="特点"><a href="#特点" class="headerlink" title="特点"></a>特点</h4><ul>
<li>顺序二叉树通常只考虑<strong>完全二叉树</strong></li>
<li>第 n个元素的<strong>左</strong>子节点为 <strong>2 × n + 1</strong></li>
<li>第 n个元素的<strong>右</strong>子节点为 <strong>2 × n + 2</strong></li>
<li>第 n个元素的<strong>父</strong>节点为 <strong>(n-1) ÷2</strong><ul>
<li>其中<strong>n</strong> 表示二叉树中的第几个元素(从0开始编号)</li>
</ul>
</li>
</ul>
<p>遍历过程和二叉树的遍历类似，只不过递归的条件有所不同</p>
<h4 id="实现代码-2"><a href="#实现代码-2" class="headerlink" title="实现代码"></a>实现代码</h4><pre><code class="hljs java"><span class="hljs-keyword">public</span> <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">Demo4</span> </span>&#123;
   <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">static</span> <span class="hljs-keyword">void</span> <span class="hljs-title">main</span><span class="hljs-params">(String[] args)</span> </span>&#123;
      <span class="hljs-keyword">int</span>[] arr = &#123;<span class="hljs-number">1</span>, <span class="hljs-number">2</span>, <span class="hljs-number">3</span>, <span class="hljs-number">4</span>, <span class="hljs-number">5</span>, <span class="hljs-number">6</span>, <span class="hljs-number">7</span>&#125;;
      ArrBinaryTree arrBinaryTree = <span class="hljs-keyword">new</span> ArrBinaryTree(arr);
      <span class="hljs-comment">//前序遍历</span>
      System.out.println(<span class="hljs-string">"数组前序遍历"</span>);
      arrBinaryTree.preTraverse();
      System.out.println();

      <span class="hljs-comment">//中序遍历</span>
      System.out.println(<span class="hljs-string">"数组中序遍历"</span>);
      arrBinaryTree.midTraverse();
      System.out.println();

      <span class="hljs-comment">//后序遍历</span>
      System.out.println(<span class="hljs-string">"数组后序遍历"</span>);
      arrBinaryTree.lastTraverse();
      System.out.println();
   &#125;
&#125;

<span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">ArrBinaryTree</span> </span>&#123;
   <span class="hljs-keyword">int</span>[] arr;
   <span class="hljs-keyword">final</span> <span class="hljs-keyword">int</span> STEP = <span class="hljs-number">2</span>;

   <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-title">ArrBinaryTree</span><span class="hljs-params">(<span class="hljs-keyword">int</span>[] arr)</span> </span>&#123;
      <span class="hljs-keyword">this</span>.arr = arr;
   &#125;

   <span class="hljs-comment">/**</span>
<span class="hljs-comment">    * 数组的前序遍历</span>
<span class="hljs-comment">    */</span>
   <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">preTraverse</span><span class="hljs-params">()</span> </span>&#123;
      preTraverse(<span class="hljs-number">0</span>);
   &#125;

   <span class="hljs-comment">/**</span>
<span class="hljs-comment">    * 数组的前序遍历</span>
<span class="hljs-comment">    * <span class="hljs-doctag">@param</span> index 遍历到的数组元素下标</span>
<span class="hljs-comment">    */</span>
   <span class="hljs-function"><span class="hljs-keyword">private</span> <span class="hljs-keyword">void</span> <span class="hljs-title">preTraverse</span><span class="hljs-params">(<span class="hljs-keyword">int</span> index)</span> </span>&#123;
      <span class="hljs-keyword">if</span>(arr == <span class="hljs-keyword">null</span> || arr.length == <span class="hljs-number">0</span>) &#123;
         System.out.println(<span class="hljs-string">"数组为空！"</span>);
         <span class="hljs-keyword">return</span>;
      &#125;
      System.out.print(arr[index] + <span class="hljs-string">" "</span>);
      <span class="hljs-comment">//向左递归</span>
      <span class="hljs-keyword">if</span>((index * STEP) + <span class="hljs-number">1</span> &lt; arr.length) &#123;
         preTraverse((index * STEP) + <span class="hljs-number">1</span>);
      &#125;
      <span class="hljs-comment">//向右递归</span>
      <span class="hljs-keyword">if</span>((index * STEP) + <span class="hljs-number">2</span> &lt; arr.length) &#123;
         preTraverse((index * STEP) + <span class="hljs-number">2</span>);
      &#125;
   &#125;

   <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">midTraverse</span><span class="hljs-params">()</span> </span>&#123;
      midTraverse(<span class="hljs-number">0</span>);
   &#125;

   <span class="hljs-function"><span class="hljs-keyword">private</span> <span class="hljs-keyword">void</span> <span class="hljs-title">midTraverse</span><span class="hljs-params">(<span class="hljs-keyword">int</span> index)</span> </span>&#123;
      <span class="hljs-keyword">if</span>(arr == <span class="hljs-keyword">null</span> || arr.length == <span class="hljs-number">0</span>) &#123;
         System.out.println(<span class="hljs-string">"数组为空!"</span>);
      &#125;

      <span class="hljs-comment">//左递归</span>
      <span class="hljs-keyword">if</span>((index * STEP) + <span class="hljs-number">1</span> &lt; arr.length) &#123;
         midTraverse((index * STEP) + <span class="hljs-number">1</span>);
      &#125;
      System.out.print(arr[index] + <span class="hljs-string">" "</span>);
      <span class="hljs-comment">//右递归</span>
      <span class="hljs-keyword">if</span>((index * STEP) + <span class="hljs-number">2</span> &lt; arr.length) &#123;
         midTraverse((index * STEP) + <span class="hljs-number">2</span>);
      &#125;
   &#125;

   <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">lastTraverse</span><span class="hljs-params">()</span> </span>&#123;
      lastTraverse(<span class="hljs-number">0</span>);
   &#125;

   <span class="hljs-function"><span class="hljs-keyword">private</span> <span class="hljs-keyword">void</span> <span class="hljs-title">lastTraverse</span><span class="hljs-params">(<span class="hljs-keyword">int</span> index)</span> </span>&#123;
      <span class="hljs-keyword">if</span>(arr == <span class="hljs-keyword">null</span> || arr.length == <span class="hljs-number">0</span>) &#123;
         System.out.println(<span class="hljs-string">"数组为空!"</span>);
      &#125;
      <span class="hljs-comment">//左递归</span>
      <span class="hljs-keyword">if</span>((index * STEP) + <span class="hljs-number">1</span> &lt; arr.length) &#123;
         lastTraverse((index * STEP) + <span class="hljs-number">1</span>);
      &#125;
      <span class="hljs-comment">//右递归</span>
      <span class="hljs-keyword">if</span>((index * STEP) + <span class="hljs-number">2</span> &lt; arr.length) &#123;
         lastTraverse((index * STEP) + <span class="hljs-number">2</span>);
      &#125;
      System.out.print(arr[index] + <span class="hljs-string">" "</span>);
   &#125;
&#125;</code></pre>



<p><strong>运行结果</strong></p>
<pre><code class="hljs angelscript">数组前序遍历
<span class="hljs-number">1</span> <span class="hljs-number">2</span> <span class="hljs-number">4</span> <span class="hljs-number">5</span> <span class="hljs-number">3</span> <span class="hljs-number">6</span> <span class="hljs-number">7</span> 
数组中序遍历
<span class="hljs-number">4</span> <span class="hljs-number">2</span> <span class="hljs-number">5</span> <span class="hljs-number">1</span> <span class="hljs-number">6</span> <span class="hljs-number">3</span> <span class="hljs-number">7</span> 
数组后序遍历
<span class="hljs-number">4</span> <span class="hljs-number">5</span> <span class="hljs-number">2</span> <span class="hljs-number">6</span> <span class="hljs-number">7</span> <span class="hljs-number">3</span> <span class="hljs-number">1</span></code></pre>



<h3 id="线索化二叉树"><a href="#线索化二叉树" class="headerlink" title="线索化二叉树"></a>线索化二叉树</h3><h4 id="基本概念"><a href="#基本概念" class="headerlink" title="基本概念"></a>基本概念</h4><p>因为一般的二叉树，叶子节点的左右指针都为空，这样就会造成<strong>空间的浪费</strong>。为了减少浪费，便有了线索化二叉树</p>
<ul>
<li><p>n个结点的二叉链表中含有 n+1 【公式 2n-(n-1)=n+1】个空指针域。利用二叉链表中的空指针域，存放指向该结点在<strong>某种遍历次序</strong>下的前驱和后继结点的指针</p>
</li>
<li><p>这种加上了线索的二叉链表称为线索链表，相应的二叉树称为线索二叉树</p>
</li>
<li><p>根据线索性质的不同，线索二叉树可分为<strong>前序</strong>线索二叉树、<strong>中序</strong>线索二叉树和<strong>后序</strong>线索二叉树三种</p>
</li>
<li><p>如果一个节点已经有了左右孩子，那么该节点就不能被线索化了，所以线索化二叉树后，节点的left和right有如下两种情况</p>
<ul>
<li>left可能指向的是左孩子，也可能指向的是前驱节点</li>
<li>right可能指向的是右孩子，也可能指向的是后继节点</li>
</ul>
</li>
</ul>
<h4 id="图解"><a href="#图解" class="headerlink" title="图解"></a>图解</h4><p><strong>中序线索化前</strong></p>
<p><img src="https://nyimapicture.oss-cn-beijing.aliyuncs.com/img/20200726155144.png" srcset="/img/loading.gif" alt=""></p>
<p><strong>中序线索化后</strong></p>
<p><img src="https://nyimapicture.oss-cn-beijing.aliyuncs.com/img/20200726155345.png" srcset="/img/loading.gif" alt=""></p>
<h4 id="实现代码-3"><a href="#实现代码-3" class="headerlink" title="实现代码"></a>实现代码</h4><p><strong>线索化思路</strong></p>
<ul>
<li>每个节点需要用两个变量来表示<strong>左右指针的类型</strong>（保存左右子树，还是前驱后继）</li>
<li>需要用两个变量来表示<strong>当前节点</strong>和当前节点的<strong>前驱节点</strong></li>
<li>通过将<strong>当前节点的左指针</strong>指向前驱节点，来实现前驱节点的绑定</li>
<li>通过将<strong>前驱节点的右指针</strong>指向当前节点，来实现后继节点的绑定</li>
</ul>
<p><strong>遍历方式</strong></p>
<ul>
<li>各个节点可以通过<strong>线性</strong>的方式遍历，无需使用递归的方式遍历</li>
<li>首先有一个外循环，代替递归操作，循环条件的暂存节点不为空</li>
<li>第一个内循环用于找到第一个元素，然后打印</li>
<li>第二个循环用于找到节点的后继元素</li>
<li>最后将暂存节点令为右孩子</li>
</ul>
<pre><code class="hljs java"><span class="hljs-keyword">public</span> <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">Demo1</span> </span>&#123;
	<span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">static</span> <span class="hljs-keyword">void</span> <span class="hljs-title">main</span><span class="hljs-params">(String[] args)</span> </span>&#123;
		<span class="hljs-comment">//初始化节点</span>
		Student student1 = <span class="hljs-keyword">new</span> Student(<span class="hljs-number">1</span>, <span class="hljs-string">"1"</span>);
		Student student2 = <span class="hljs-keyword">new</span> Student(<span class="hljs-number">2</span>, <span class="hljs-string">"3"</span>);
		Student student3 = <span class="hljs-keyword">new</span> Student(<span class="hljs-number">3</span>, <span class="hljs-string">"6"</span>);
		Student student4 = <span class="hljs-keyword">new</span> Student(<span class="hljs-number">4</span>, <span class="hljs-string">"8"</span>);
		Student student5 = <span class="hljs-keyword">new</span> Student(<span class="hljs-number">5</span>, <span class="hljs-string">"10"</span>);
		Student student6 = <span class="hljs-keyword">new</span> Student(<span class="hljs-number">6</span>, <span class="hljs-string">"14"</span>);

		<span class="hljs-comment">//手动创建二叉树</span>
		ThreadedBinaryTree tree = <span class="hljs-keyword">new</span> ThreadedBinaryTree();
		student1.setLeft(student2);
		student1.setRight(student3);
		student2.setLeft(student4);
		student2.setRight(student5);
		student3.setLeft(student6);

		tree.setRoot(student1);

		tree.midThreaded();

		<span class="hljs-comment">//得到第五个节点的前驱节点和后继节点</span>
		System.out.println(<span class="hljs-string">"第五个节点的前驱节点和后继节点"</span>);
		System.out.println(student5.getLeft());
		System.out.println(student5.getRight());

		<span class="hljs-comment">//遍历线索化二叉树</span>
		System.out.println(<span class="hljs-string">"遍历线索化二叉树"</span>);
		tree.midThreadedTraverse();

	&#125;
&#125;

<span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">ThreadedBinaryTree</span> </span>&#123;
	<span class="hljs-keyword">private</span> Student root;
	<span class="hljs-comment">/**</span>
<span class="hljs-comment">	 * 指向当前节点的前一个节点</span>
<span class="hljs-comment">	 */</span>
	<span class="hljs-keyword">private</span> Student pre;

	<span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">setRoot</span><span class="hljs-params">(Student root)</span> </span>&#123;
		<span class="hljs-keyword">this</span>.root = root;
	&#125;

	<span class="hljs-comment">/**</span>
<span class="hljs-comment">	 * 中序线索化</span>
<span class="hljs-comment">	 * <span class="hljs-doctag">@param</span> node 当前节点</span>
<span class="hljs-comment">	 */</span>
	<span class="hljs-function"><span class="hljs-keyword">private</span> <span class="hljs-keyword">void</span> <span class="hljs-title">midThreaded</span><span class="hljs-params">(Student node)</span> </span>&#123;
		<span class="hljs-keyword">if</span>(node == <span class="hljs-keyword">null</span>) &#123;
			<span class="hljs-keyword">return</span>;
		&#125;
		<span class="hljs-comment">//左线索化</span>
		midThreaded(node.getLeft());
        
		<span class="hljs-comment">//线索化当前节点</span>
		<span class="hljs-comment">//如果当前节点的左指针为空，就指向前驱节点，并改变左指针类型</span>
		<span class="hljs-keyword">if</span>(node.getLeft() == <span class="hljs-keyword">null</span>) &#123;
			node.setLeft(pre);
			node.setLeftType(<span class="hljs-number">1</span>);
		&#125;
		<span class="hljs-comment">//通过前驱节点来将右指针的值令为后继节点</span>
		<span class="hljs-keyword">if</span>(pre != <span class="hljs-keyword">null</span> &amp;&amp; pre.getRight() == <span class="hljs-keyword">null</span>) &#123;
			pre.setRight(node);
			pre.setRightType(<span class="hljs-number">1</span>);
		&#125;

		<span class="hljs-comment">//处理一个节点后，让当前节点变为下一个节点的前驱节点</span>
		pre = node;

		<span class="hljs-comment">//右线索化</span>
		midThreaded(node.getRight());
	&#125;

	<span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">midThreaded</span><span class="hljs-params">()</span> </span>&#123;
		midThreaded(root);
	&#125;

	<span class="hljs-comment">/**</span>
<span class="hljs-comment">	 * 遍历线索化后的二叉树</span>
<span class="hljs-comment">	 */</span>
	<span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">midThreadedTraverse</span><span class="hljs-params">()</span> </span>&#123;
		<span class="hljs-comment">//暂存遍历到的节点</span>
		Student tempNode = root;
		<span class="hljs-comment">//非递归的方法遍历，如果tempNode不为空就一直循环</span>
		<span class="hljs-keyword">while</span>(tempNode != <span class="hljs-keyword">null</span>) &#123;
			<span class="hljs-comment">//一直访问二叉树的左子树，直到某个节点的左子树指向前驱节点</span>
			<span class="hljs-keyword">while</span>(tempNode.getLeftType() != <span class="hljs-number">1</span>) &#123;
				tempNode = tempNode.getLeft();
			&#125;
			<span class="hljs-comment">//找到了第一个节点</span>
			System.out.println(tempNode);
			<span class="hljs-comment">//再访问该节点的右子树，看是否保存了后继节点</span>
			<span class="hljs-comment">//如果是，则打印该节点的后继节点信息</span>
			<span class="hljs-keyword">while</span>(tempNode.getRightType() == <span class="hljs-number">1</span>) &#123;
				tempNode = tempNode.getRight();
				System.out.println(tempNode);
			&#125;

			tempNode = tempNode.getRight();
		&#125;

	&#125;
&#125;

<span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">Student</span> </span>&#123;
	<span class="hljs-keyword">private</span> <span class="hljs-keyword">int</span> id;
	<span class="hljs-keyword">private</span> String name;
	<span class="hljs-keyword">private</span> Student left;
	<span class="hljs-keyword">private</span> Student right;
	<span class="hljs-comment">/**</span>
<span class="hljs-comment">	 * 左、右指针的类型，0--&gt;指向的是左右孩子，1--&gt;指向的是前驱、后续节点</span>
<span class="hljs-comment">	 */</span>
	<span class="hljs-keyword">private</span> <span class="hljs-keyword">int</span> leftType = <span class="hljs-number">0</span>;
	<span class="hljs-keyword">private</span> <span class="hljs-keyword">int</span> rightType = <span class="hljs-number">0</span>;

	<span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-title">Student</span><span class="hljs-params">(<span class="hljs-keyword">int</span> id, String name)</span> </span>&#123;
		<span class="hljs-keyword">this</span>.id = id;
		<span class="hljs-keyword">this</span>.name = name;
	&#125;

	<span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">int</span> <span class="hljs-title">getId</span><span class="hljs-params">()</span> </span>&#123;
		<span class="hljs-keyword">return</span> id;
	&#125;

	<span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">setId</span><span class="hljs-params">(<span class="hljs-keyword">int</span> id)</span> </span>&#123;
		<span class="hljs-keyword">this</span>.id = id;
	&#125;

	<span class="hljs-function"><span class="hljs-keyword">public</span> String <span class="hljs-title">getName</span><span class="hljs-params">()</span> </span>&#123;
		<span class="hljs-keyword">return</span> name;
	&#125;

	<span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">setName</span><span class="hljs-params">(String name)</span> </span>&#123;
		<span class="hljs-keyword">this</span>.name = name;
	&#125;

	<span class="hljs-function"><span class="hljs-keyword">public</span> Student <span class="hljs-title">getLeft</span><span class="hljs-params">()</span> </span>&#123;
		<span class="hljs-keyword">return</span> left;
	&#125;

	<span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">setLeft</span><span class="hljs-params">(Student left)</span> </span>&#123;
		<span class="hljs-keyword">this</span>.left = left;
	&#125;

	<span class="hljs-function"><span class="hljs-keyword">public</span> Student <span class="hljs-title">getRight</span><span class="hljs-params">()</span> </span>&#123;
		<span class="hljs-keyword">return</span> right;
	&#125;

	<span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">setRight</span><span class="hljs-params">(Student right)</span> </span>&#123;
		<span class="hljs-keyword">this</span>.right = right;
	&#125;

	<span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">int</span> <span class="hljs-title">getLeftType</span><span class="hljs-params">()</span> </span>&#123;
		<span class="hljs-keyword">return</span> leftType;
	&#125;

	<span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">setLeftType</span><span class="hljs-params">(<span class="hljs-keyword">int</span> leftType)</span> </span>&#123;
		<span class="hljs-keyword">this</span>.leftType = leftType;
	&#125;

	<span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">int</span> <span class="hljs-title">getRightType</span><span class="hljs-params">()</span> </span>&#123;
		<span class="hljs-keyword">return</span> rightType;
	&#125;

	<span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">setRightType</span><span class="hljs-params">(<span class="hljs-keyword">int</span> rightType)</span> </span>&#123;
		<span class="hljs-keyword">this</span>.rightType = rightType;
	&#125;

	<span class="hljs-meta">@Override</span>
	<span class="hljs-function"><span class="hljs-keyword">public</span> String <span class="hljs-title">toString</span><span class="hljs-params">()</span> </span>&#123;
		<span class="hljs-keyword">return</span> <span class="hljs-string">"Student&#123;"</span> +
				<span class="hljs-string">"id="</span> + id +
				<span class="hljs-string">", name='"</span> + name + <span class="hljs-string">'\''</span> +
				<span class="hljs-string">'&#125;'</span>;
	&#125;
&#125;</code></pre>



<p><strong>运行结果</strong></p>
<pre><code class="hljs routeros">第五个节点的前驱节点和后继节点
Student&#123;<span class="hljs-attribute">id</span>=2, <span class="hljs-attribute">name</span>=<span class="hljs-string">'3'</span>&#125;
Student&#123;<span class="hljs-attribute">id</span>=1, <span class="hljs-attribute">name</span>=<span class="hljs-string">'1'</span>&#125;
遍历线索化二叉树
Student&#123;<span class="hljs-attribute">id</span>=4, <span class="hljs-attribute">name</span>=<span class="hljs-string">'8'</span>&#125;
Student&#123;<span class="hljs-attribute">id</span>=2, <span class="hljs-attribute">name</span>=<span class="hljs-string">'3'</span>&#125;
Student&#123;<span class="hljs-attribute">id</span>=5, <span class="hljs-attribute">name</span>=<span class="hljs-string">'10'</span>&#125;
Student&#123;<span class="hljs-attribute">id</span>=1, <span class="hljs-attribute">name</span>=<span class="hljs-string">'1'</span>&#125;
Student&#123;<span class="hljs-attribute">id</span>=6, <span class="hljs-attribute">name</span>=<span class="hljs-string">'14'</span>&#125;
Student&#123;<span class="hljs-attribute">id</span>=3, <span class="hljs-attribute">name</span>=<span class="hljs-string">'6'</span>&#125;</code></pre>



<h2 id="2、树的应用"><a href="#2、树的应用" class="headerlink" title="2、树的应用"></a>2、树的应用</h2><h3 id="堆排序"><a href="#堆排序" class="headerlink" title="堆排序"></a>堆排序</h3><p>详见<a href="https://nyimac.gitee.io/2020/06/17/%E6%95%B0%E6%8D%AE%E7%BB%93%E6%9E%84%E4%B8%8E%E7%AE%97%E6%B3%95/#11%E3%80%81%E5%A0%86%E6%8E%92%E5%BA%8F">排序算法——堆排序</a></p>
<h3 id="哈夫曼树"><a href="#哈夫曼树" class="headerlink" title="哈夫曼树"></a>哈夫曼树</h3><p><img src="https://nyimapicture.oss-cn-beijing.aliyuncs.com/img/20200727192923.png" srcset="/img/loading.gif" alt=""></p>
<h4 id="基本介绍"><a href="#基本介绍" class="headerlink" title="基本介绍"></a>基本介绍</h4><ul>
<li>给定 n个权值作为 n个叶子结点，构造一棵二叉树，<strong>若该树的带权路径长度(wpl)达到最小</strong>，称这样的二叉树为最优二叉树，也称为哈夫曼树(Huffman Tree)</li>
<li>哈夫曼树是带权路径长度最短的树，<strong>权值较大的结点离根较近</strong></li>
</ul>
<h4 id="重要概念"><a href="#重要概念" class="headerlink" title="重要概念"></a>重要概念</h4><ul>
<li><strong>路径和路径长度</strong>：在一棵树中，从一个结点往下可以达到的孩子或孙子结点之间的通路，称为路径。<strong>通路中分支的数目称为路径长度</strong>。若规定根结点的层数为1，则从根结点到第L层结点的路径长度为 <strong>L-1</strong></li>
<li><strong>结点的权及带权路径长度</strong>：若将树中结点赋给一个有着某种含义的数值，则这个数值称为该<strong>结点的权</strong>。<ul>
<li><strong>结点的带权路径长度为</strong>：从根结点到该结点之间的路径长度与该结点的权的<strong>乘积</strong>（W×L）</li>
</ul>
</li>
<li><strong>树的带权路径长度</strong>：树的带权路径长度规定为<strong>所有叶子结点的带权路径长度之和</strong>（W1×L1+W2×L2…），记为WPL(weighted pathlength) ,权值越大的结点离根结点越近的二叉树才是最优二叉树。</li>
<li>WPL最小的就是哈夫曼树</li>
</ul>
<h4 id="创建思路及图解"><a href="#创建思路及图解" class="headerlink" title="创建思路及图解"></a>创建思路及图解</h4><p><strong>创建思路</strong></p>
<ul>
<li>从小到大进行排序, 将每一个数据，每个数据都是一个节点 ， 每个节点可以看成是一颗最简单的二叉树</li>
<li>取出<strong>根节点权值最小</strong>的两颗二叉树</li>
<li>组成一颗新的二叉树, 该新的二叉树的根节点的权值是前面两颗二叉树<strong>根节点权值的和</strong></li>
<li>再将这颗新的二叉树，以<strong>根节点的权值大小 再次排序</strong>，不断重复 1-2-3-4 的步骤，直到数列中，所有的数据都被处理，就得到一颗赫夫曼树</li>
</ul>
<p><strong>图解</strong></p>
<p>以{3, 6, 7, 1, 8, 29, 13}为例</p>
<p><strong>首先排序</strong>：{1, 3, 6, 7, 8, 13, 29}</p>
<p><img src="https://nyimapicture.oss-cn-beijing.aliyuncs.com/img/20200729185121.png" srcset="/img/loading.gif" alt=""></p>
<p><img src="https://nyimapicture.oss-cn-beijing.aliyuncs.com/img/20200729185142.png" srcset="/img/loading.gif" alt=""></p>
<p><img src="https://nyimapicture.oss-cn-beijing.aliyuncs.com/img/20200729185223.png" srcset="/img/loading.gif" alt=""></p>
<p><img src="https://nyimapicture.oss-cn-beijing.aliyuncs.com/img/20200729185340.png" srcset="/img/loading.gif" alt=""></p>
<p><img src="https://nyimapicture.oss-cn-beijing.aliyuncs.com/img/20200729185434.png" srcset="/img/loading.gif" alt=""></p>
<p><img src="https://nyimapicture.oss-cn-beijing.aliyuncs.com/img/20200729185516.png" srcset="/img/loading.gif" alt=""></p>
<h4 id="实现代码-4"><a href="#实现代码-4" class="headerlink" title="实现代码"></a>实现代码</h4><pre><code class="hljs java"><span class="hljs-keyword">public</span> <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">Demo1</span> </span>&#123;
   <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">static</span> <span class="hljs-keyword">void</span> <span class="hljs-title">main</span><span class="hljs-params">(String[] args)</span> </span>&#123;
      <span class="hljs-keyword">int</span>[] arr = &#123;<span class="hljs-number">3</span>, <span class="hljs-number">6</span>, <span class="hljs-number">7</span>, <span class="hljs-number">1</span>, <span class="hljs-number">8</span>, <span class="hljs-number">29</span>, <span class="hljs-number">13</span>&#125;;
      HuffmanTree huffmanTree = <span class="hljs-keyword">new</span> HuffmanTree();
      Node root = huffmanTree.createHuffmanTree(arr);
      root.preTraverse();
   &#125;
&#125;

<span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">HuffmanTree</span> </span>&#123;

   <span class="hljs-function"><span class="hljs-keyword">public</span> Node <span class="hljs-title">createHuffmanTree</span><span class="hljs-params">(<span class="hljs-keyword">int</span>[] arr)</span> </span>&#123;
      <span class="hljs-comment">//创建数组用于存放Node</span>
      ArrayList&lt;Node&gt; nodes = <span class="hljs-keyword">new</span> ArrayList&lt;&gt;(arr.length);
      <span class="hljs-keyword">for</span>(<span class="hljs-keyword">int</span> value : arr) &#123;
         nodes.add(<span class="hljs-keyword">new</span> Node(value));
      &#125;
      <span class="hljs-comment">//对集合中的元素进行排序</span>
      Collections.sort(nodes);

      <span class="hljs-keyword">while</span>(nodes.size() &gt; <span class="hljs-number">1</span>) &#123;
         <span class="hljs-comment">//左右子树在集合中对应的下标</span>
         <span class="hljs-keyword">int</span> leftIndex = <span class="hljs-number">0</span>;
         <span class="hljs-keyword">int</span> rightIndex = <span class="hljs-number">1</span>;

         <span class="hljs-comment">//取出最小的两个节点</span>
         Node leftNode = nodes.get(leftIndex);
         Node rightNode = nodes.get(rightIndex);
         <span class="hljs-comment">//创建父节点，并创建左右子树</span>
         Node parent = <span class="hljs-keyword">new</span> Node(leftNode.value + rightNode.value);
         parent.left = leftNode;
         parent.right = rightNode;
         <span class="hljs-comment">//从集合中移除两个最小的节点，并将父节点放入集合中</span>
         nodes.add(parent);
         nodes.remove(leftNode);
         nodes.remove(rightNode);
         <span class="hljs-comment">//再次比较</span>
         Collections.sort(nodes);
      &#125;
      <span class="hljs-comment">//返回根节点</span>
      <span class="hljs-keyword">return</span> nodes.get(<span class="hljs-number">0</span>);
   &#125;
&#125;

<span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">Node</span> <span class="hljs-keyword">implements</span> <span class="hljs-title">Comparable</span>&lt;<span class="hljs-title">Node</span>&gt; </span>&#123;
   <span class="hljs-keyword">int</span> value;
   Node left;
   Node right;

   <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-title">Node</span><span class="hljs-params">(<span class="hljs-keyword">int</span> value)</span> </span>&#123;
      <span class="hljs-keyword">this</span>.value = value;
   &#125;

   <span class="hljs-meta">@Override</span>
   <span class="hljs-function"><span class="hljs-keyword">public</span> String <span class="hljs-title">toString</span><span class="hljs-params">()</span> </span>&#123;
      <span class="hljs-keyword">return</span> <span class="hljs-string">"Node&#123;"</span> +
            <span class="hljs-string">"value="</span> + value +
            <span class="hljs-string">'&#125;'</span>;
   &#125;

   <span class="hljs-comment">/**</span>
<span class="hljs-comment">    * 重写比较函数，用于排序</span>
<span class="hljs-comment">    */</span>
   <span class="hljs-meta">@Override</span>
   <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">int</span> <span class="hljs-title">compareTo</span><span class="hljs-params">(Node o)</span> </span>&#123;
      <span class="hljs-keyword">return</span> value - o.value;
   &#125;

   <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">preTraverse</span><span class="hljs-params">()</span> </span>&#123;
      System.out.print(<span class="hljs-keyword">this</span>.value + <span class="hljs-string">" "</span>);
      <span class="hljs-keyword">if</span> (<span class="hljs-keyword">this</span>.left != <span class="hljs-keyword">null</span>) &#123;
         <span class="hljs-keyword">this</span>.left.preTraverse();
      &#125;
      <span class="hljs-keyword">if</span> (<span class="hljs-keyword">this</span>.right != <span class="hljs-keyword">null</span>) &#123;
         <span class="hljs-keyword">this</span>.right.preTraverse();
      &#125;
   &#125;
&#125;</code></pre>

<p><strong>运行结果</strong></p>
<pre><code class="hljs java">前序遍历哈夫曼树
<span class="hljs-number">67</span> <span class="hljs-number">29</span> <span class="hljs-number">38</span> <span class="hljs-number">15</span> <span class="hljs-number">7</span> <span class="hljs-number">8</span> <span class="hljs-number">23</span> <span class="hljs-number">10</span> <span class="hljs-number">4</span> <span class="hljs-number">1</span> <span class="hljs-number">3</span> <span class="hljs-number">6</span> <span class="hljs-number">13</span></code></pre>



<h3 id="哈夫曼编码"><a href="#哈夫曼编码" class="headerlink" title="哈夫曼编码"></a>哈夫曼编码</h3><h4 id="原理及图解"><a href="#原理及图解" class="headerlink" title="原理及图解"></a>原理及图解</h4><p><strong>前缀编码</strong>：任何一个字符的编码，都不会是其它的字符的前缀</p>
<ul>
<li>统计需编码的字符串中，各个字符出现的次数：如helloworld<ul>
<li>h:1 e:1 w:1 r:1 d:1 o:2 l:3</li>
</ul>
</li>
<li>将字符出现的次数作为权值，构建哈弗曼树。如下图</li>
</ul>
<p><img src="https://nyimapicture.oss-cn-beijing.aliyuncs.com/img/20200728190229.png" srcset="/img/loading.gif" alt=""></p>
<ul>
<li>根据哈弗曼树进行编码，向左的路径为0，向右的路径为1<ul>
<li>字符编码结果为：h:000 e:001 w:100 d:1010 r:1011 l:11 o:01</li>
<li>字符串编码结果为：000001111101100011011111010</li>
</ul>
</li>
</ul>
<h4 id="实现代码-5"><a href="#实现代码-5" class="headerlink" title="实现代码"></a>实现代码</h4><p>此处代码只实现了哈弗曼树的创建与每个字符的编码</p>
<pre><code class="hljs java"><span class="hljs-keyword">public</span> <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">Demo2</span> </span>&#123;
   <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">static</span> <span class="hljs-keyword">void</span> <span class="hljs-title">main</span><span class="hljs-params">(String[] args)</span> </span>&#123;
      String str = <span class="hljs-string">"helloworld"</span>;
      <span class="hljs-comment">//哈夫曼编码</span>
      HuffmanCode huffmanCode = <span class="hljs-keyword">new</span> HuffmanCode();
      ArrayList&lt;Code&gt; list = huffmanCode.getList(str);
      <span class="hljs-comment">//构建哈弗曼树</span>
      Code root = huffmanCode.createHuffmanTree(list);
      System.out.println(<span class="hljs-string">"前序遍历哈弗曼树"</span>);
      root.preTraverse();
      <span class="hljs-comment">//进行哈弗曼编码</span>
      Map&lt;Byte, String&gt; codeMap = root.getCodeMap();
      System.out.println(<span class="hljs-string">"哈弗曼编码"</span>);
      System.out.println(codeMap);
   &#125;
&#125;

<span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">HuffmanCode</span> </span>&#123;
   <span class="hljs-function"><span class="hljs-keyword">public</span> ArrayList&lt;Code&gt; <span class="hljs-title">getList</span><span class="hljs-params">(String codes)</span> </span>&#123;
      <span class="hljs-comment">//得到字符串对应的字节数组</span>
      <span class="hljs-keyword">byte</span>[] byteCodes = codes.getBytes();

      <span class="hljs-comment">//创建哈希表，用于存放数据及其权值（出现次数）</span>
      Map&lt;Byte, Integer&gt; dataAndWight = <span class="hljs-keyword">new</span> HashMap&lt;&gt;();
      <span class="hljs-keyword">for</span>(<span class="hljs-keyword">byte</span> b : byteCodes) &#123;
         Integer wight = dataAndWight.get(b);
         <span class="hljs-comment">//如果还没有该数据，就创建并让其权值为1</span>
         <span class="hljs-keyword">if</span>(dataAndWight.get(b) == <span class="hljs-keyword">null</span>) &#123;
            dataAndWight.put(b, <span class="hljs-number">1</span>);
         &#125;<span class="hljs-keyword">else</span> &#123;
            <span class="hljs-comment">//如果已经有了该数据，就让其权值加一</span>
            dataAndWight.put(b, wight+<span class="hljs-number">1</span>);
         &#125;
      &#125;

      <span class="hljs-comment">//创建List，用于返回</span>
      ArrayList&lt;Code&gt; list = <span class="hljs-keyword">new</span> ArrayList&lt;&gt;();
      <span class="hljs-comment">//遍历哈希表，放入List集合中</span>
      <span class="hljs-keyword">for</span>(Map.Entry&lt;Byte, Integer&gt; entry : dataAndWight.entrySet()) &#123;
         list.add(<span class="hljs-keyword">new</span> Code(entry.getKey(), entry.getValue()));
      &#125;
      <span class="hljs-keyword">return</span> list;
   &#125;

   <span class="hljs-function"><span class="hljs-keyword">public</span> Code <span class="hljs-title">createHuffmanTree</span><span class="hljs-params">(ArrayList&lt;Code&gt; lists)</span> </span>&#123;
      <span class="hljs-keyword">int</span> leftIndex = <span class="hljs-number">0</span>;
      <span class="hljs-keyword">int</span> rightIndex = <span class="hljs-number">1</span>;
      <span class="hljs-comment">//根据权值进行排序</span>
      Collections.sort(lists);

      <span class="hljs-keyword">while</span> (lists.size() &gt; <span class="hljs-number">1</span>) &#123;
         Code leftCode = lists.get(leftIndex);
         Code rightCode = lists.get(rightIndex);
         Code parent = <span class="hljs-keyword">new</span> Code(<span class="hljs-keyword">null</span>,leftCode.weight + rightCode.weight);
         parent.left = leftCode;
         parent.right = rightCode;
         lists.add(parent);
         lists.remove(leftCode);
         lists.remove(rightCode);
         <span class="hljs-comment">//再次排序</span>
         Collections.sort(lists);
      &#125;
      <span class="hljs-keyword">return</span> lists.get(<span class="hljs-number">0</span>);
   &#125;
&#125;

<span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">Code</span> <span class="hljs-keyword">implements</span> <span class="hljs-title">Comparable</span>&lt;<span class="hljs-title">Code</span>&gt; </span>&#123;
   Byte data;
   <span class="hljs-keyword">int</span> weight;
   Code left;
   Code right;
   <span class="hljs-keyword">private</span> Map&lt;Byte, String&gt; codeMap = <span class="hljs-keyword">new</span> HashMap&lt;&gt;();



   <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-title">Code</span><span class="hljs-params">(Byte data, <span class="hljs-keyword">int</span> weight)</span> </span>&#123;
      <span class="hljs-keyword">this</span>.data = data;
      <span class="hljs-keyword">this</span>.weight = weight;
   &#125;

   <span class="hljs-meta">@Override</span>
   <span class="hljs-function"><span class="hljs-keyword">public</span> String <span class="hljs-title">toString</span><span class="hljs-params">()</span> </span>&#123;
      <span class="hljs-keyword">return</span> <span class="hljs-string">"Code&#123;"</span> +
            <span class="hljs-string">"data="</span> + data +
            <span class="hljs-string">", weight="</span> + weight +
            <span class="hljs-string">'&#125;'</span>;
   &#125;

   <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">preTraverse</span><span class="hljs-params">()</span> </span>&#123;
      System.out.println(<span class="hljs-keyword">this</span>);
      <span class="hljs-keyword">if</span>(left != <span class="hljs-keyword">null</span>) &#123;
         left.preTraverse();
      &#125;
      <span class="hljs-keyword">if</span>(right != <span class="hljs-keyword">null</span>) &#123;
         right.preTraverse();
      &#125;
   &#125;

   <span class="hljs-function"><span class="hljs-keyword">public</span> Map&lt;Byte, String&gt; <span class="hljs-title">getCodeMap</span><span class="hljs-params">()</span> </span>&#123;
      <span class="hljs-keyword">return</span> getCode(<span class="hljs-keyword">this</span>, <span class="hljs-string">""</span>, <span class="hljs-keyword">new</span> StringBuilder());
   &#125;

   <span class="hljs-comment">/**</span>
<span class="hljs-comment">    * 对哈弗曼树中的叶子节点进行编码</span>
<span class="hljs-comment">    * <span class="hljs-doctag">@param</span> node 根节点</span>
<span class="hljs-comment">    * <span class="hljs-doctag">@param</span> code 左子树为0，右子树为1</span>
<span class="hljs-comment">    * <span class="hljs-doctag">@param</span> stringBuilder 用于拼接的字符串</span>
<span class="hljs-comment">    * <span class="hljs-doctag">@return</span></span>
<span class="hljs-comment">    */</span>
   <span class="hljs-function"><span class="hljs-keyword">private</span> Map&lt;Byte, String&gt; <span class="hljs-title">getCode</span><span class="hljs-params">(Code node, String code, StringBuilder stringBuilder)</span> </span>&#123;
      <span class="hljs-comment">//新建拼接路径</span>
      StringBuilder appendCode = <span class="hljs-keyword">new</span> StringBuilder(stringBuilder);
      appendCode.append(code);
      <span class="hljs-keyword">if</span>(node != <span class="hljs-keyword">null</span>) &#123;
         <span class="hljs-comment">//如果是非叶子结点，就继续向下遍历</span>
         <span class="hljs-keyword">if</span>(node.data == <span class="hljs-keyword">null</span>) &#123;
            getCode(node.left, <span class="hljs-string">"0"</span>, appendCode);
            getCode(node.right, <span class="hljs-string">"1"</span>, appendCode);
         &#125;<span class="hljs-keyword">else</span> &#123;
            <span class="hljs-comment">//如果是叶子节点，就将哈弗曼编码放入哈希表中</span>
            codeMap.put(node.data, appendCode.toString());
         &#125;
      &#125;
      <span class="hljs-keyword">return</span> codeMap;
   &#125;

   <span class="hljs-meta">@Override</span>
   <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">int</span> <span class="hljs-title">compareTo</span><span class="hljs-params">(Code o)</span> </span>&#123;
      <span class="hljs-keyword">return</span> weight - o.weight;
   &#125;
&#125;</code></pre>

<p><strong>运行结果</strong></p>
<pre><code class="hljs java">前序遍历哈弗曼树
Code&#123;data=<span class="hljs-keyword">null</span>, weight=<span class="hljs-number">10</span>&#125;
Code&#123;data=<span class="hljs-keyword">null</span>, weight=<span class="hljs-number">4</span>&#125;
Code&#123;data=<span class="hljs-keyword">null</span>, weight=<span class="hljs-number">2</span>&#125;
Code&#123;data=<span class="hljs-number">114</span>, weight=<span class="hljs-number">1</span>&#125;
Code&#123;data=<span class="hljs-number">100</span>, weight=<span class="hljs-number">1</span>&#125;
Code&#123;data=<span class="hljs-keyword">null</span>, weight=<span class="hljs-number">2</span>&#125;
Code&#123;data=<span class="hljs-number">101</span>, weight=<span class="hljs-number">1</span>&#125;
Code&#123;data=<span class="hljs-number">119</span>, weight=<span class="hljs-number">1</span>&#125;
Code&#123;data=<span class="hljs-keyword">null</span>, weight=<span class="hljs-number">6</span>&#125;
Code&#123;data=<span class="hljs-number">108</span>, weight=<span class="hljs-number">3</span>&#125;
Code&#123;data=<span class="hljs-keyword">null</span>, weight=<span class="hljs-number">3</span>&#125;
Code&#123;data=<span class="hljs-number">104</span>, weight=<span class="hljs-number">1</span>&#125;
Code&#123;data=<span class="hljs-number">111</span>, weight=<span class="hljs-number">2</span>&#125;
每个字符对应的哈弗曼编码
&#123;<span class="hljs-number">114</span>=<span class="hljs-number">000</span>, <span class="hljs-number">100</span>=<span class="hljs-number">001</span>, <span class="hljs-number">101</span>=<span class="hljs-number">010</span>, <span class="hljs-number">119</span>=<span class="hljs-number">011</span>, <span class="hljs-number">104</span>=<span class="hljs-number">110</span>, <span class="hljs-number">108</span>=<span class="hljs-number">10</span>, <span class="hljs-number">111</span>=<span class="hljs-number">111</span>&#125;</code></pre>



<h3 id="二叉排序树"><a href="#二叉排序树" class="headerlink" title="二叉排序树"></a>二叉排序树</h3><h4 id="基本介绍-1"><a href="#基本介绍-1" class="headerlink" title="基本介绍"></a>基本介绍</h4><p><strong>二叉排序树</strong>：BST: (Binary Sort(Search) Tree), 对于二叉排序树的<strong>任何一个非叶子节点</strong>，要求<strong>左子节点的值比当前节点的值小，右子节点的值比当前节点的值大</strong></p>
<ul>
<li><strong>特别说明</strong>：如果有相同的值，可以将该节点放在左子节点或右子节点</li>
</ul>
<p> 比如针对前面的数据 (7, 3, 10, 12, 5, 1, 9) ，对应的二叉排序树为：</p>
<p><img src="https://nyimapicture.oss-cn-beijing.aliyuncs.com/img/20200729161543.png" srcset="/img/loading.gif" alt=""></p>
<h4 id="操作思路"><a href="#操作思路" class="headerlink" title="操作思路"></a>操作思路</h4><p><strong>添加</strong></p>
<ul>
<li>根据插入节点的值来寻找其应该插入的位置</li>
<li>新插入的节点都是<strong>叶子节点</strong></li>
</ul>
<p><strong>删除</strong></p>
<p>删除<strong>叶子节点</strong>（如删除值为2节点）</p>
<ul>
<li>找到待删除的节点</li>
<li>找到待删除节点的父节点</li>
<li>判断待删除节点是其<strong>父节点</strong>的左孩子还是右孩子，然后让其令为空</li>
</ul>
<p>删除<strong>只有一颗子树的节点</strong>（如删除值为1的节点）</p>
<ul>
<li>找到待删除的节点</li>
<li>找到待删除的节点的父节点</li>
<li>判断待删除节点是其<strong>父节点</strong>的左孩子还是右孩子</li>
<li>判断待删除节点的<strong>子树</strong>是其左孩子还是右孩子</li>
<li>让父节点指向待删除节点的子树指向待删除节点的子树</li>
</ul>
<p>删除有<strong>两颗子树的节点</strong>（如删除值为3的节点）</p>
<ul>
<li>找到待删除的节点</li>
<li>找到待删除的节点的父节点</li>
<li>判断待删除节点是其<strong>父节点</strong>的左孩子还是右孩子</li>
<li>顺着待删除节点的<strong>右子树</strong>，找到一个值最小的节点（该值的大小最接近待删除节点的值）</li>
<li>让父节点指向待删除节点的子树指向上一步找到的最小的节点</li>
</ul>
<p>删除<strong>根节点</strong>（如删除值为7的节点）</p>
<ul>
<li>删除根结点的方法和删除有两个子树的方法相似</li>
<li>找到一个接近根节点值的节点</li>
<li>删除该节点，将该节点的值赋值给根节点即可</li>
</ul>
<h4 id="实现代码-6"><a href="#实现代码-6" class="headerlink" title="实现代码"></a>实现代码</h4><pre><code class="hljs java"><span class="hljs-keyword">public</span> <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">Demo1</span> </span>&#123;
   <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">static</span> <span class="hljs-keyword">void</span> <span class="hljs-title">main</span><span class="hljs-params">(String[] args)</span> </span>&#123;
      <span class="hljs-keyword">int</span>[] arr = &#123;<span class="hljs-number">7</span>, <span class="hljs-number">3</span>, <span class="hljs-number">10</span>, <span class="hljs-number">12</span>, <span class="hljs-number">5</span>, <span class="hljs-number">1</span>, <span class="hljs-number">9</span>, <span class="hljs-number">2</span>&#125;;
      <span class="hljs-comment">//创建二叉排序树</span>
      BinarySortTree binarySortTree = <span class="hljs-keyword">new</span> BinarySortTree();
      <span class="hljs-keyword">for</span> (<span class="hljs-keyword">int</span> i = <span class="hljs-number">0</span>; i &lt; arr.length; i++) &#123;
         binarySortTree.addNode(<span class="hljs-keyword">new</span> Node(arr[i]));
      &#125;
      <span class="hljs-comment">//前序遍历</span>
      System.out.println(<span class="hljs-string">"前序遍历二叉排序树"</span>);
      binarySortTree.preTraverse();
      System.out.println();
      <span class="hljs-comment">//删除值为5、1、3、10、7的节点</span>
      binarySortTree.deleteNode(<span class="hljs-number">2</span>);
      binarySortTree.deleteNode(<span class="hljs-number">1</span>);
      binarySortTree.deleteNode(<span class="hljs-number">10</span>);
      binarySortTree.deleteNode(<span class="hljs-number">7</span>);
      System.out.println(<span class="hljs-string">"前序遍历二叉排序树"</span>);
      binarySortTree.preTraverse();
   &#125;
&#125;

<span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">BinarySortTree</span> </span>&#123;
   <span class="hljs-keyword">private</span> Node root;

   <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">addNode</span><span class="hljs-params">(Node node)</span> </span>&#123;
      <span class="hljs-comment">//如果根节点为空，就直接将该节点作为根节点</span>
      <span class="hljs-keyword">if</span> (root == <span class="hljs-keyword">null</span>) &#123;
         root = node;
         <span class="hljs-keyword">return</span>;
      &#125;
      <span class="hljs-comment">//否则就插入该节点到对应的位置</span>
      root.add(node);
   &#125;

   <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">preTraverse</span><span class="hljs-params">()</span> </span>&#123;
      <span class="hljs-keyword">if</span>(root == <span class="hljs-keyword">null</span>) &#123;
         System.out.println(<span class="hljs-string">"二叉树为空"</span>);
      &#125; <span class="hljs-keyword">else</span> &#123;
         root.preTraverse();
      &#125;
   &#125;

   <span class="hljs-function"><span class="hljs-keyword">public</span> Node <span class="hljs-title">getTargetNode</span><span class="hljs-params">(<span class="hljs-keyword">int</span> targetValue)</span> </span>&#123;
      <span class="hljs-keyword">if</span> (root == <span class="hljs-keyword">null</span>) &#123;
         System.out.println(<span class="hljs-string">"请先创建二叉树"</span>);
         <span class="hljs-keyword">return</span> <span class="hljs-keyword">null</span>;
      &#125; <span class="hljs-keyword">else</span> &#123;
         <span class="hljs-keyword">return</span> root.getTargetNode(targetValue);
      &#125;
   &#125;

   <span class="hljs-function"><span class="hljs-keyword">public</span> Node <span class="hljs-title">getParentNode</span><span class="hljs-params">(<span class="hljs-keyword">int</span> targetValue)</span> </span>&#123;
      <span class="hljs-keyword">if</span> (root == <span class="hljs-keyword">null</span>) &#123;
         System.out.println(<span class="hljs-string">"请先创建二叉树"</span>);
         <span class="hljs-keyword">return</span> <span class="hljs-keyword">null</span>;
      &#125; <span class="hljs-keyword">else</span> &#123;
         <span class="hljs-keyword">return</span> root.getParentNode(targetValue);
      &#125;
   &#125;

   <span class="hljs-comment">/**</span>
<span class="hljs-comment">    * 删除节点</span>
<span class="hljs-comment">    *</span>
<span class="hljs-comment">    * <span class="hljs-doctag">@param</span> targetValue 待删除节点的值</span>
<span class="hljs-comment">    */</span>
   <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">deleteNode</span><span class="hljs-params">(<span class="hljs-keyword">int</span> targetValue)</span> </span>&#123;
      <span class="hljs-keyword">if</span> (root == <span class="hljs-keyword">null</span>) &#123;
         System.out.println(<span class="hljs-string">"请先创建二叉树"</span>);
         <span class="hljs-keyword">return</span>;
      &#125;

      <span class="hljs-comment">//找到待删除结点</span>
      Node targetNode = getTargetNode(targetValue);
      <span class="hljs-keyword">if</span> (targetNode == <span class="hljs-keyword">null</span>) &#123;
         System.out.println(<span class="hljs-string">"未找到该节点，删除失败"</span>);
         <span class="hljs-keyword">return</span>;
      &#125;
      <span class="hljs-comment">//如果只有一个根节点，就删除根节点</span>
      <span class="hljs-keyword">if</span>(root.left == <span class="hljs-keyword">null</span> &amp;&amp; root.right == <span class="hljs-keyword">null</span>) &#123;
         root = <span class="hljs-keyword">null</span>;
         System.out.println(<span class="hljs-string">"删除成功"</span>);
         <span class="hljs-keyword">return</span>;
      &#125;

      <span class="hljs-comment">//得到其父节点</span>
      Node parentNode = getParentNode(targetValue);
      <span class="hljs-comment">//如果父节点为空（待删除节点为根节点）</span>
      <span class="hljs-keyword">if</span>(parentNode == <span class="hljs-keyword">null</span>) &#123;
         <span class="hljs-keyword">int</span> minValue = getMinValue(targetNode.right);
         deleteNode(minValue);
         <span class="hljs-comment">//根节点的值令为最接近的值</span>
         targetNode.value = minValue;
         <span class="hljs-keyword">return</span>;
      &#125;

      <span class="hljs-comment">//如果待删除节点为叶子节点</span>
      <span class="hljs-keyword">if</span> (targetNode.left == <span class="hljs-keyword">null</span> &amp;&amp; targetNode.right == <span class="hljs-keyword">null</span>) &#123;
         <span class="hljs-keyword">if</span> (parentNode.left != <span class="hljs-keyword">null</span> &amp;&amp; parentNode.left == targetNode) &#123;
            <span class="hljs-comment">//删除左子树</span>
            parentNode.left = <span class="hljs-keyword">null</span>;
            System.out.println(<span class="hljs-string">"删除成功"</span>);
         &#125; <span class="hljs-keyword">else</span> <span class="hljs-keyword">if</span> (parentNode.right != <span class="hljs-keyword">null</span> &amp;&amp; parentNode.right == targetNode) &#123;
            <span class="hljs-comment">//删除右子树</span>
            parentNode.right = <span class="hljs-keyword">null</span>;
            System.out.println(<span class="hljs-string">"删除成功"</span>);
         &#125;
      &#125; <span class="hljs-keyword">else</span> <span class="hljs-keyword">if</span> (targetNode.left != <span class="hljs-keyword">null</span> &amp;&amp; targetNode.right != <span class="hljs-keyword">null</span>) &#123;
         <span class="hljs-comment">//待删除节点有左右子树</span>
         <span class="hljs-comment">//得到并删除待删除节点右子树中值最小的节点</span>
         <span class="hljs-keyword">int</span> minValue = getMinValue(targetNode.right);
         deleteNode(minValue);
         <span class="hljs-comment">//将值最小的节点的值作为新的目标节点</span>
         targetNode.value = minValue;
      &#125; <span class="hljs-keyword">else</span> &#123;
         <span class="hljs-comment">//待删除节点只有左子树</span>
         <span class="hljs-keyword">if</span>(targetNode.left != <span class="hljs-keyword">null</span>) &#123;
            <span class="hljs-keyword">if</span>(parentNode.left != <span class="hljs-keyword">null</span> &amp;&amp; parentNode.left == targetNode) &#123;
               parentNode.left = targetNode.left;
            &#125; <span class="hljs-keyword">else</span> <span class="hljs-keyword">if</span> (parentNode.right != <span class="hljs-keyword">null</span> &amp;&amp; parentNode.right == targetNode) &#123;
               parentNode.right = targetNode.left;
            &#125;
         &#125; <span class="hljs-keyword">else</span> &#123;
            <span class="hljs-comment">//待删除节点只有右子树</span>
            <span class="hljs-keyword">if</span>(parentNode.left != <span class="hljs-keyword">null</span> &amp;&amp; parentNode.left == targetNode) &#123;
               parentNode.left = targetNode.right;
            &#125; <span class="hljs-keyword">else</span> <span class="hljs-keyword">if</span> (parentNode.right != <span class="hljs-keyword">null</span> &amp;&amp; parentNode.right == targetNode) &#123;
               parentNode.right = targetNode.right;
            &#125;
         &#125;
      &#125;
   &#125;

   <span class="hljs-comment">/**</span>
<span class="hljs-comment">    * 找到以node为根节点的二叉树的最小节点的值</span>
<span class="hljs-comment">    * <span class="hljs-doctag">@param</span> node 作为根节点的节点</span>
<span class="hljs-comment">    * <span class="hljs-doctag">@return</span> 值最小的节点的值</span>
<span class="hljs-comment">    */</span>
   <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">int</span> <span class="hljs-title">getMinValue</span><span class="hljs-params">(Node node)</span> </span>&#123;
      <span class="hljs-keyword">while</span>(node.left != <span class="hljs-keyword">null</span>) &#123;
         node = node.left;
      &#125;
      <span class="hljs-comment">//返回值最小的节点</span>
      <span class="hljs-keyword">return</span> node.value;
   &#125;
&#125;


<span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">Node</span> </span>&#123;
   <span class="hljs-keyword">int</span> value;
   Node left;
   Node right;

   <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-title">Node</span><span class="hljs-params">(<span class="hljs-keyword">int</span> value)</span> </span>&#123;
      <span class="hljs-keyword">this</span>.value = value;
   &#125;

   <span class="hljs-meta">@Override</span>
   <span class="hljs-function"><span class="hljs-keyword">public</span> String <span class="hljs-title">toString</span><span class="hljs-params">()</span> </span>&#123;
      <span class="hljs-keyword">return</span> <span class="hljs-string">"Node&#123;"</span> +
            <span class="hljs-string">"value="</span> + value +
            <span class="hljs-string">'&#125;'</span>;
   &#125;

   <span class="hljs-comment">/**</span>
<span class="hljs-comment">    * 添加节点到二叉排序树的对应位置</span>
<span class="hljs-comment">    *</span>
<span class="hljs-comment">    * <span class="hljs-doctag">@param</span> node 待插入的节点</span>
<span class="hljs-comment">    */</span>
   <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">add</span><span class="hljs-params">(Node node)</span> </span>&#123;
      <span class="hljs-keyword">if</span> (node == <span class="hljs-keyword">null</span>) &#123;
         <span class="hljs-keyword">return</span>;
      &#125;
      <span class="hljs-comment">//如果该节点的值大待插入节点的值</span>
      <span class="hljs-keyword">if</span> (value &gt; node.value) &#123;
         <span class="hljs-comment">//如果该节点的左子树为空，就直接插入</span>
         <span class="hljs-keyword">if</span> (left == <span class="hljs-keyword">null</span>) &#123;
            left = node;
         &#125; <span class="hljs-keyword">else</span> &#123;
            left.add(node);
         &#125;
      &#125; <span class="hljs-keyword">else</span> &#123;
         <span class="hljs-keyword">if</span> (right == <span class="hljs-keyword">null</span>) &#123;
            right = node;
         &#125; <span class="hljs-keyword">else</span> &#123;
            right.add(node);
         &#125;
      &#125;
   &#125;

   <span class="hljs-comment">/**</span>
<span class="hljs-comment">    * 前序遍历</span>
<span class="hljs-comment">    */</span>
   <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">preTraverse</span><span class="hljs-params">()</span> </span>&#123;
      System.out.println(<span class="hljs-keyword">this</span>);
      <span class="hljs-keyword">if</span> (left != <span class="hljs-keyword">null</span>) &#123;
         left.preTraverse();
      &#125;
      <span class="hljs-keyword">if</span> (right != <span class="hljs-keyword">null</span>) &#123;
         right.preTraverse();
      &#125;
   &#125;

   <span class="hljs-comment">/**</span>
<span class="hljs-comment">    * 得到目标节点</span>
<span class="hljs-comment">    *</span>
<span class="hljs-comment">    * <span class="hljs-doctag">@param</span> targetValue 目标节点的值</span>
<span class="hljs-comment">    * <span class="hljs-doctag">@return</span> 目标节点</span>
<span class="hljs-comment">    */</span>
   <span class="hljs-function"><span class="hljs-keyword">public</span> Node <span class="hljs-title">getTargetNode</span><span class="hljs-params">(<span class="hljs-keyword">int</span> targetValue)</span> </span>&#123;
      <span class="hljs-comment">//如果当前节点就是目标节点，就返回</span>
      <span class="hljs-keyword">if</span> (value == targetValue) &#123;
         <span class="hljs-keyword">return</span> <span class="hljs-keyword">this</span>;
      &#125;
      <span class="hljs-comment">//如果当前节点的值大于目标节点，就向左查找，反之向右查找</span>
      <span class="hljs-keyword">if</span> (value &gt; targetValue) &#123;
         <span class="hljs-keyword">if</span> (left == <span class="hljs-keyword">null</span>) &#123;
            <span class="hljs-keyword">return</span> <span class="hljs-keyword">null</span>;
         &#125; <span class="hljs-keyword">else</span> &#123;
            <span class="hljs-keyword">return</span> left.getTargetNode(targetValue);
         &#125;
      &#125; <span class="hljs-keyword">else</span> &#123;
         <span class="hljs-keyword">if</span> (right == <span class="hljs-keyword">null</span>) &#123;
            <span class="hljs-keyword">return</span> <span class="hljs-keyword">null</span>;
         &#125; <span class="hljs-keyword">else</span> &#123;
            <span class="hljs-keyword">return</span> right.getTargetNode(targetValue);
         &#125;
      &#125;
   &#125;

   <span class="hljs-comment">/**</span>
<span class="hljs-comment">    * 得到目标节点的父节点</span>
<span class="hljs-comment">    *</span>
<span class="hljs-comment">    * <span class="hljs-doctag">@param</span> targetValue 目标节点的值</span>
<span class="hljs-comment">    * <span class="hljs-doctag">@return</span> 目标节点的父节点</span>
<span class="hljs-comment">    */</span>
   <span class="hljs-function"><span class="hljs-keyword">public</span> Node <span class="hljs-title">getParentNode</span><span class="hljs-params">(<span class="hljs-keyword">int</span> targetValue)</span> </span>&#123;
      <span class="hljs-comment">//如果左右子树是目标节点，就返回该节点，否则继续向下查找</span>
      <span class="hljs-keyword">if</span> (left != <span class="hljs-keyword">null</span> &amp;&amp; left.value == targetValue) &#123;
         <span class="hljs-keyword">return</span> <span class="hljs-keyword">this</span>;
      &#125; <span class="hljs-keyword">else</span> <span class="hljs-keyword">if</span> (right != <span class="hljs-keyword">null</span> &amp;&amp; right.value == targetValue) &#123;
         <span class="hljs-keyword">return</span> <span class="hljs-keyword">this</span>;
      &#125; <span class="hljs-keyword">else</span> &#123;
         <span class="hljs-keyword">if</span> (left != <span class="hljs-keyword">null</span> &amp;&amp; value &gt; targetValue) &#123;
            <span class="hljs-keyword">return</span> left.getParentNode(targetValue);
         &#125;
         <span class="hljs-keyword">if</span> (right != <span class="hljs-keyword">null</span> &amp;&amp; value &lt;= targetValue) &#123;
            <span class="hljs-keyword">return</span> right.getParentNode(targetValue);
         &#125; <span class="hljs-keyword">else</span> &#123;
            <span class="hljs-comment">//没有父节点（根节点）</span>
            <span class="hljs-keyword">return</span> <span class="hljs-keyword">null</span>;
         &#125;
      &#125;
   &#125;
&#125;</code></pre>



<p><strong>运行结果</strong></p>
<pre><code class="hljs crmsh">前序遍历二叉排序树
<span class="hljs-keyword">Node</span><span class="hljs-title">&#123;value</span>=<span class="hljs-number">7</span>&#125;
<span class="hljs-keyword">Node</span><span class="hljs-title">&#123;value</span>=<span class="hljs-number">3</span>&#125;
<span class="hljs-keyword">Node</span><span class="hljs-title">&#123;value</span>=<span class="hljs-number">1</span>&#125;
<span class="hljs-keyword">Node</span><span class="hljs-title">&#123;value</span>=<span class="hljs-number">2</span>&#125;
<span class="hljs-keyword">Node</span><span class="hljs-title">&#123;value</span>=<span class="hljs-number">5</span>&#125;
<span class="hljs-keyword">Node</span><span class="hljs-title">&#123;value</span>=<span class="hljs-number">10</span>&#125;
<span class="hljs-keyword">Node</span><span class="hljs-title">&#123;value</span>=<span class="hljs-number">9</span>&#125;
<span class="hljs-keyword">Node</span><span class="hljs-title">&#123;value</span>=<span class="hljs-number">12</span>&#125;

删除成功
删除成功
删除成功
删除成功
前序遍历二叉排序树
<span class="hljs-keyword">Node</span><span class="hljs-title">&#123;value</span>=<span class="hljs-number">9</span>&#125;
<span class="hljs-keyword">Node</span><span class="hljs-title">&#123;value</span>=<span class="hljs-number">3</span>&#125;
<span class="hljs-keyword">Node</span><span class="hljs-title">&#123;value</span>=<span class="hljs-number">5</span>&#125;
<span class="hljs-keyword">Node</span><span class="hljs-title">&#123;value</span>=<span class="hljs-number">12</span>&#125;</code></pre>



<h3 id="平衡二叉树"><a href="#平衡二叉树" class="headerlink" title="平衡二叉树"></a>平衡二叉树</h3><h4 id="基本介绍-2"><a href="#基本介绍-2" class="headerlink" title="基本介绍"></a>基本介绍</h4><p><strong>为什么需要平衡二叉树</strong></p>
<ul>
<li>如果由数组{1, 2, 3, 4}来构建一颗二叉排序树，得到的二叉树不仅没有体现其特点，反而还退化成了链表</li>
</ul>
<p><img src="https://nyimapicture.oss-cn-beijing.aliyuncs.com/img/20200730152912.png" srcset="/img/loading.gif" alt=""></p>
<p><strong>简介</strong></p>
<ul>
<li><p>平衡二叉树也叫平衡<strong>二叉搜索树</strong>（Self-balancing binary search tree）又被称为AVL树，可以保证<strong>查询效率较高</strong></p>
</li>
<li><p>具有以下特点：</p>
<ul>
<li><strong>它是一棵空树</strong>或<strong>它的左右两个子树的高度差的绝对值不超过</strong> <strong>1</strong>，并且<strong>左右两个子树都是一棵平衡二叉树</strong></li>
<li>平衡二叉树的常用实现方法有红黑树、AVL、替罪羊树、Treap、伸展树等</li>
</ul>
</li>
<li><p>下图所示的二叉树就是平衡二叉树</p>
</li>
</ul>
<p><img src="https://nyimapicture.oss-cn-beijing.aliyuncs.com/img/20200730153215.png" srcset="/img/loading.gif" alt=""></p>
<h4 id="应用案例——左旋转"><a href="#应用案例——左旋转" class="headerlink" title="应用案例——左旋转"></a>应用案例——左旋转</h4><p>将由数列 {4,3,6,5,7,8}构建的二叉排序树，修改为一颗平衡二叉树</p>
<p>此处<strong>右子树的高度高于左子树，且差值大于1</strong>，所以需要进行<strong>左旋转</strong>，来降低右子树的高度</p>
<p><img src="https://nyimapicture.oss-cn-beijing.aliyuncs.com/img/20200730154440.png" srcset="/img/loading.gif" alt=""></p>
<p><strong>步骤</strong></p>
<ul>
<li>创建一个新节点，值为当前节点的值（4）</li>
</ul>
<p><img src="https://nyimapicture.oss-cn-beijing.aliyuncs.com/img/20200730200322.png" srcset="/img/loading.gif" alt=""></p>
<ul>
<li>让新节点的左子树指向当前节点的左子树</li>
</ul>
<p><img src="https://nyimapicture.oss-cn-beijing.aliyuncs.com/img/20200730154609.png" srcset="/img/loading.gif" alt=""></p>
<ul>
<li>让新节点的右子树指向当前节点的右子树的左子树</li>
</ul>
<p><img src="https://nyimapicture.oss-cn-beijing.aliyuncs.com/img/20200730155228.png" srcset="/img/loading.gif" alt=""></p>
<ul>
<li><p>将当前节点的值改为其右子树的值</p>
<p><img src="https://nyimapicture.oss-cn-beijing.aliyuncs.com/img/20200730155216.png" srcset="/img/loading.gif" alt=""></p>
</li>
<li><p>将当前节点的右子树变为其右子树的右子树</p>
</li>
</ul>
<p><img src="https://nyimapicture.oss-cn-beijing.aliyuncs.com/img/20200730155146.png" srcset="/img/loading.gif" alt=""></p>
<ul>
<li>让当前节点的左子树指向新节点</li>
</ul>
<p><img src="https://nyimapicture.oss-cn-beijing.aliyuncs.com/img/20200730155127.png" srcset="/img/loading.gif" alt=""></p>
<p><strong>整理后结果</strong></p>
<p><img src="https://nyimapicture.oss-cn-beijing.aliyuncs.com/img/20200730155105.png" srcset="/img/loading.gif" alt=""></p>
<h4 id="应用案例——右旋转"><a href="#应用案例——右旋转" class="headerlink" title="应用案例——右旋转"></a>应用案例——右旋转</h4><p>当一颗二叉排序树的<strong>左子树高度大于右子树高度，且差值大于1</strong>时，需要进行右旋转，来降低左子树的高度</p>
<p><strong>步骤</strong></p>
<ul>
<li>创建一个新节点，其值为当前节点的值</li>
<li>将新节点的右子树指向当前节点的右子树</li>
<li>将新节点的左子树指向当前节点的左子树的右子树</li>
<li>将当前节点的值改为其左子树的值</li>
<li>将当前节点的左子树指向其左子树的左子树</li>
<li>将当前节点的右子树指向新节点</li>
</ul>
<h4 id="应用案例——双旋转"><a href="#应用案例——双旋转" class="headerlink" title="应用案例——双旋转"></a>应用案例——双旋转</h4><p>某些时候，只进行左旋转或者右旋转，并不能将二叉排序树变为平衡二叉树。这时就需要进行<strong>双旋转</strong>，即<strong>同时进行左旋转和右旋转</strong></p>
<ul>
<li>进行左旋转时，如果当前节点右子树的左子树高于其右子树，需要先进行左旋转</li>
</ul>
<p><img src="https://nyimapicture.oss-cn-beijing.aliyuncs.com/img/20200730171100.png" srcset="/img/loading.gif" alt=""></p>
<ul>
<li>进行右旋转时，如果当前节点左子树的右子树高于其左子树，需要先进性右旋转</li>
</ul>
<p><img src="https://nyimapicture.oss-cn-beijing.aliyuncs.com/img/20200730171151.png" srcset="/img/loading.gif" alt=""></p>
<h4 id="实现代码-7"><a href="#实现代码-7" class="headerlink" title="实现代码"></a>实现代码</h4><pre><code class="hljs java"><span class="hljs-keyword">public</span> <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">Demo1</span> </span>&#123;
   <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">static</span> <span class="hljs-keyword">void</span> <span class="hljs-title">main</span><span class="hljs-params">(String[] args)</span> </span>&#123;
      <span class="hljs-keyword">int</span>[] arr = &#123;<span class="hljs-number">10</span>, <span class="hljs-number">7</span>, <span class="hljs-number">11</span>, <span class="hljs-number">5</span>, <span class="hljs-number">8</span>, <span class="hljs-number">9</span>&#125;;
      AVLTree tree = <span class="hljs-keyword">new</span> AVLTree();
      <span class="hljs-keyword">for</span> (<span class="hljs-keyword">int</span> value : arr) &#123;
         tree.addNode(<span class="hljs-keyword">new</span> Node(value));
      &#125;
      System.out.println(<span class="hljs-string">"左右子树高度差值为 "</span> + tree.getDifference());
      System.out.println(<span class="hljs-string">"前序遍历"</span>);
      tree.preTraverse();
   &#125;
&#125;

<span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">AVLTree</span> </span>&#123;
   <span class="hljs-keyword">private</span> Node root;


   <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">addNode</span><span class="hljs-params">(Node node)</span> </span>&#123;
      <span class="hljs-comment">//如果根节点为空，就直接将该节点作为根节点</span>
      <span class="hljs-keyword">if</span> (root == <span class="hljs-keyword">null</span>) &#123;
         root = node;
         <span class="hljs-keyword">return</span>;
      &#125;
      <span class="hljs-comment">//否则就插入该节点到对应的位置</span>
      root.add(node);
   &#125;

   <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">preTraverse</span><span class="hljs-params">()</span> </span>&#123;
      <span class="hljs-keyword">if</span>(root == <span class="hljs-keyword">null</span>) &#123;
         System.out.println(<span class="hljs-string">"二叉树为空"</span>);
      &#125; <span class="hljs-keyword">else</span> &#123;
         root.preTraverse();
      &#125;
   &#125;

   <span class="hljs-comment">/**</span>
<span class="hljs-comment">    * 找到以node为根节点的二叉树的最小节点的值</span>
<span class="hljs-comment">    * <span class="hljs-doctag">@param</span> node 作为根节点的节点</span>
<span class="hljs-comment">    * <span class="hljs-doctag">@return</span> 值最小的节点的值</span>
<span class="hljs-comment">    */</span>
   <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">int</span> <span class="hljs-title">getMinValue</span><span class="hljs-params">(Node node)</span> </span>&#123;
      <span class="hljs-keyword">while</span>(node.left != <span class="hljs-keyword">null</span>) &#123;
         node = node.left;
      &#125;
      <span class="hljs-comment">//返回值最小的节点</span>
      <span class="hljs-keyword">return</span> node.value;
   &#125;

   <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">int</span> <span class="hljs-title">getDifference</span><span class="hljs-params">()</span> </span>&#123;
      <span class="hljs-keyword">int</span> leftHeight = root.getLeftHeight();
      <span class="hljs-keyword">int</span> rightHeight = root.getRightHeight();
      <span class="hljs-comment">//返回左右子树高度差值</span>
      <span class="hljs-keyword">return</span> Math.abs(leftHeight - rightHeight);
   &#125;
&#125;

<span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">Node</span> </span>&#123;
   <span class="hljs-keyword">int</span> value;
   Node left;
   Node right;

   <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-title">Node</span><span class="hljs-params">(<span class="hljs-keyword">int</span> value)</span> </span>&#123;
      <span class="hljs-keyword">this</span>.value = value;
   &#125;

   <span class="hljs-meta">@Override</span>
   <span class="hljs-function"><span class="hljs-keyword">public</span> String <span class="hljs-title">toString</span><span class="hljs-params">()</span> </span>&#123;
      <span class="hljs-keyword">return</span> <span class="hljs-string">"Node&#123;"</span> +
            <span class="hljs-string">"value="</span> + value +
            <span class="hljs-string">'&#125;'</span>;
   &#125;

   <span class="hljs-comment">/**</span>
<span class="hljs-comment">    * 添加节点到二叉排序树的对应位置</span>
<span class="hljs-comment">    *</span>
<span class="hljs-comment">    * <span class="hljs-doctag">@param</span> node 待插入的节点</span>
<span class="hljs-comment">    */</span>
   <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">add</span><span class="hljs-params">(Node node)</span> </span>&#123;
      <span class="hljs-keyword">if</span> (node == <span class="hljs-keyword">null</span>) &#123;
         <span class="hljs-keyword">return</span>;
      &#125;
      <span class="hljs-comment">//如果该节点的值大待插入节点的值</span>
      <span class="hljs-keyword">if</span> (value &gt; node.value) &#123;
         <span class="hljs-comment">//如果该节点的左子树为空，就直接插入</span>
         <span class="hljs-keyword">if</span> (left == <span class="hljs-keyword">null</span>) &#123;
            left = node;
         &#125; <span class="hljs-keyword">else</span> &#123;
            left.add(node);
         &#125;
      &#125; <span class="hljs-keyword">else</span> &#123;
         <span class="hljs-keyword">if</span> (right == <span class="hljs-keyword">null</span>) &#123;
            right = node;
         &#125; <span class="hljs-keyword">else</span> &#123;
            right.add(node);
         &#125;
      &#125;

      <span class="hljs-comment">//如果右子树高度与左子树高度差值大于一，就进行左旋转</span>
      <span class="hljs-keyword">if</span>(getRightHeight() - getLeftHeight() &gt; <span class="hljs-number">1</span>) &#123;
         <span class="hljs-comment">//如果当前节点右子树的左子树高度高于右子树，其右子树先进行右旋转</span>
         <span class="hljs-keyword">if</span>(right.getLeftHeight() &gt; right.getRightHeight()) &#123;
            right.rightRotate();
         &#125;
         leftRotate();
      &#125;
      <span class="hljs-comment">//如果左子树高度与右子树的高度差值大于一，就进行右旋转</span>
      <span class="hljs-keyword">if</span>(getLeftHeight() - getRightHeight() &gt; <span class="hljs-number">1</span>) &#123;
         <span class="hljs-comment">//如果当前节点左子树的右子树高度高于左子树，其左子树先进行左旋转</span>
         <span class="hljs-keyword">if</span>(left.getRightHeight() &gt; left.getLeftHeight()) &#123;
            left.leftRotate();
         &#125;
         rightRotate();
      &#125;
   &#125;

   <span class="hljs-comment">/**</span>
<span class="hljs-comment">    * 前序遍历</span>
<span class="hljs-comment">    */</span>
   <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">preTraverse</span><span class="hljs-params">()</span> </span>&#123;
      System.out.println(<span class="hljs-keyword">this</span>);
      <span class="hljs-keyword">if</span> (left != <span class="hljs-keyword">null</span>) &#123;
         left.preTraverse();
      &#125;
      <span class="hljs-keyword">if</span> (right != <span class="hljs-keyword">null</span>) &#123;
         right.preTraverse();
      &#125;
   &#125;
   
   <span class="hljs-comment">/**</span>
<span class="hljs-comment">    * 获得该节点为根节点的树的高度</span>
<span class="hljs-comment">    *</span>
<span class="hljs-comment">    * <span class="hljs-doctag">@return</span> 高度</span>
<span class="hljs-comment">    */</span>
   <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">int</span> <span class="hljs-title">getHeight</span><span class="hljs-params">()</span> </span>&#123;
      <span class="hljs-keyword">return</span> Math.max(left == <span class="hljs-keyword">null</span> ? <span class="hljs-number">0</span> : left.getHeight(), right == <span class="hljs-keyword">null</span> ? <span class="hljs-number">0</span> : right.getHeight()) + <span class="hljs-number">1</span>;
   &#125;

   <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">int</span> <span class="hljs-title">getLeftHeight</span><span class="hljs-params">()</span> </span>&#123;
      <span class="hljs-keyword">if</span>(left == <span class="hljs-keyword">null</span>) &#123;
         <span class="hljs-keyword">return</span> <span class="hljs-number">0</span>;
      &#125; <span class="hljs-keyword">else</span> &#123;
         <span class="hljs-keyword">return</span> left.getHeight();
      &#125;
   &#125;

   <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">int</span> <span class="hljs-title">getRightHeight</span><span class="hljs-params">()</span> </span>&#123;
      <span class="hljs-keyword">if</span>(right == <span class="hljs-keyword">null</span>) &#123;
         <span class="hljs-keyword">return</span> <span class="hljs-number">0</span>;
      &#125; <span class="hljs-keyword">else</span> &#123;
         <span class="hljs-keyword">return</span> right.getHeight();
      &#125;
   &#125;

   <span class="hljs-comment">/**</span>
<span class="hljs-comment">    * 对二叉排序树进行左旋转（右子树高度较高）</span>
<span class="hljs-comment">    */</span>
   <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">leftRotate</span><span class="hljs-params">()</span> </span>&#123;
      <span class="hljs-comment">//创建新节点</span>
      Node newNode = <span class="hljs-keyword">new</span> Node(value);
      <span class="hljs-comment">//新节点的左子树指向当前节点的左子树</span>
      newNode.left = left;
      <span class="hljs-comment">//新节点的右子树指向当前节点的右子树的左子树</span>
      newNode.right = right.left;
      <span class="hljs-comment">//当前节点的值变为其右子树的值</span>
      value = right.value;
      <span class="hljs-comment">//当前节点的右子树指向其右子树的右子树</span>
      right = right.right;
      <span class="hljs-comment">//当前节点的左子树指向新节点</span>
      left = newNode;
   &#125;

   <span class="hljs-comment">/**</span>
<span class="hljs-comment">    * 对二叉树进行右旋转（左子树高度较高）</span>
<span class="hljs-comment">    */</span>
   <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">rightRotate</span><span class="hljs-params">()</span> </span>&#123;
      <span class="hljs-comment">//创建新节点，值为当前节点的值</span>
      Node newNode = <span class="hljs-keyword">new</span> Node(value);
      <span class="hljs-comment">//新节点的右子树为当前节点的右子树</span>
      newNode.right = right;
      <span class="hljs-comment">//新节点的左子树为当前节点的左子树的右子树</span>
      newNode.left = left.right;
      <span class="hljs-comment">//当前节点的值为其左子树的值</span>
      value = left.value;
      <span class="hljs-comment">//当前节点的左子树为其左子树的左子树</span>
      left = left.left;
      <span class="hljs-comment">//当前节点的右子树为新节点</span>
      right = newNode;
   &#125;
&#125;</code></pre>



<p><strong>运行结果</strong></p>
<pre><code class="hljs crmsh">左右子树高度差值为 <span class="hljs-number">0</span>
前序遍历
<span class="hljs-keyword">Node</span><span class="hljs-title">&#123;value</span>=<span class="hljs-number">8</span>&#125;
<span class="hljs-keyword">Node</span><span class="hljs-title">&#123;value</span>=<span class="hljs-number">7</span>&#125;
<span class="hljs-keyword">Node</span><span class="hljs-title">&#123;value</span>=<span class="hljs-number">5</span>&#125;
<span class="hljs-keyword">Node</span><span class="hljs-title">&#123;value</span>=<span class="hljs-number">10</span>&#125;
<span class="hljs-keyword">Node</span><span class="hljs-title">&#123;value</span>=<span class="hljs-number">9</span>&#125;
<span class="hljs-keyword">Node</span><span class="hljs-title">&#123;value</span>=<span class="hljs-number">11</span>&#125;</code></pre>



<h2 id="3、多叉树"><a href="#3、多叉树" class="headerlink" title="3、多叉树"></a>3、多叉树</h2><h3 id="基本介绍-3"><a href="#基本介绍-3" class="headerlink" title="基本介绍"></a>基本介绍</h3><p>在二叉树中，每个节点最多有<strong>一个</strong>数据项和<strong>两个</strong>子节点。如果允许每个节点可以有更多的数据项和更多的子节点，就是多叉树（multiway tree）</p>
<p>多叉树通过重新组织节点，<strong>减少树的高度，能对二叉树进行优化</strong></p>
<h3 id="2-3树"><a href="#2-3树" class="headerlink" title="2-3树"></a>2-3树</h3><p><img src="https://nyimapicture.oss-cn-beijing.aliyuncs.com/img/20200730195237.png" srcset="/img/loading.gif" alt=""></p>
<p><strong>2-3树是最简单的B树结构，具有以下特点</strong></p>
<ul>
<li>2-3树的所有<strong>叶子节点都在同一层</strong>(只要是 B树都满足这个条件)</li>
<li>有两个子节点的节点叫<strong>二节点</strong>，二节点要么没有子节点，要么有两个子节点</li>
<li>有三个子节点的节点叫三节点，三节点要么没有子节点，要么有三个子节点</li>
<li>2-3树是由<strong>二节点和三节点构成的树</strong>（2和3）</li>
</ul>
<p><strong>2-3树插入规则</strong></p>
<ul>
<li><p>2-3树的所有<strong>叶子节点都在同一层</strong>.(只要是 B树都满足这个条件)</p>
</li>
<li><p>有两个子节点的节点叫二节点，二节点要么没有子节点，要么有两个子节点</p>
</li>
<li><p>有三个子节点的节点叫三节点，三节点要么没有子节点，要么有三个子节点</p>
</li>
<li><p>当按照规则插入一个数到某个节点时，不能满足上面三个要求，就需要拆，<strong>先向上拆，如果上层满，则拆本层，拆后仍然需要满足上面 3个条件</strong></p>
</li>
<li><p>对于三节点的子树的值大小仍然遵守(BST 二叉排序树)的规则</p>
<ul>
<li>左边的子树值小于父节点的值</li>
<li>中间的子树值在父节点的值之间</li>
<li>右边子树的值大于父节点的值</li>
</ul>
</li>
</ul>
<h3 id="B树、B-和B-树"><a href="#B树、B-和B-树" class="headerlink" title="B树、B+和B*树"></a>B树、B+和B*树</h3><h4 id="B树"><a href="#B树" class="headerlink" title="B树"></a><strong>B树</strong></h4><p><img src="https://nyimapicture.oss-cn-beijing.aliyuncs.com/img/20200730192248.png" srcset="/img/loading.gif" alt=""></p>
<ul>
<li><p>B树的阶：节点的<strong>最多子节点个数</strong>。比如 2-3树的阶是3，2-3-4树的阶是4</p>
</li>
<li><p>B树的搜索，从根结点开始，对结点内的关键字（有序）序列进行二分查找，如果命中则结束，否则进入查询关键字所属范围的儿子结点；重复，直到所对应的儿子指针为空，或已经是叶子结点</p>
</li>
<li><p>关键字集合分布在整颗树中, 即叶子节点和非叶子节点都存放数据</p>
</li>
<li><p>搜索<strong>有可能在非叶子结点结束</strong></p>
</li>
<li><p>其搜索性能等价于在关键字全集内做一次二分查找</p>
</li>
</ul>
<h4 id="B-树"><a href="#B-树" class="headerlink" title="B+树"></a><strong>B+树</strong></h4><p><img src="https://nyimapicture.oss-cn-beijing.aliyuncs.com/img/20200730193949.png" srcset="/img/loading.gif" alt=""></p>
<ul>
<li>B+树是B树的变体，也是一种多路搜索树</li>
<li>B+树的搜索与 B树也基本相同，区别是 B+树只有达到叶子结点才命中（B树可以在非叶子结点命中），其性能也等价于在关键字全集做一次二分查找</li>
<li><strong>所有关键字都出现在叶子结点的链表中</strong>（即数据只能在叶子节点【也叫<strong>稠密索引</strong>】），且链表中的关键字(数据)恰好是有序的</li>
<li><strong>不可能在非叶子结点命中</strong></li>
<li><strong>非叶子结点</strong>相当于是叶子结点的<strong>索引</strong>（稀疏索引），<strong>叶子结点</strong>相当于是存储（关键字）<strong>数据</strong>的数据层</li>
<li>更适合文件索引系统</li>
<li>B树和 B+树各有自己的应用场景，不能说 B+树完全比 B树好，反之亦然</li>
</ul>
<h4 id="B-树-1"><a href="#B-树-1" class="headerlink" title="B*树"></a><strong>B*树</strong></h4><p><img src="https://nyimapicture.oss-cn-beijing.aliyuncs.com/img/20200801002754.png" srcset="/img/loading.gif" alt=""></p>
<ul>
<li><p>B*树是 B+树的变体，在 B+树的非根和非叶子结点再增加指向兄弟的指针</p>
</li>
<li><p>B*树定义了非叶子结点关键字个数至少为(2/3)M，即块的最低使用率为 2/3，而B+树的块的最低使用率为的1/2</p>
</li>
<li><p>从第 1个特点我们可以看出，B*树分配新结点的概率比B+树要低，空间使用率更高</p>
</li>
</ul>
<h1 id="九、图结构"><a href="#九、图结构" class="headerlink" title="九、图结构"></a>九、图结构</h1><h2 id="1、基本介绍-1"><a href="#1、基本介绍-1" class="headerlink" title="1、基本介绍"></a>1、基本介绍</h2><h3 id="定义-1"><a href="#定义-1" class="headerlink" title="定义"></a>定义</h3><ul>
<li><p>当我们需要表示<strong>多对多</strong>的关系时，我们就需要<strong>图</strong></p>
</li>
<li><p>图是一种<strong>数据结构</strong>，其中结点可以具有零个或多个相邻元素。两个结点之间的连接称为<strong>边</strong>。结点也可以称为顶点</p>
</li>
</ul>
<p><img src="https://nyimapicture.oss-cn-beijing.aliyuncs.com/img/20200731153146.png" srcset="/img/loading.gif" alt=""></p>
<h3 id="表示方法"><a href="#表示方法" class="headerlink" title="表示方法"></a>表示方法</h3><h4 id="邻接矩阵"><a href="#邻接矩阵" class="headerlink" title="邻接矩阵"></a>邻接矩阵</h4><ul>
<li>邻接矩阵是表示图形中<strong>顶点之间相邻关系</strong>的矩阵，对于n个顶点的图而言，矩阵是的row和 col表示的是1…n个点</li>
</ul>
<p>如上图的邻接矩阵就是</p>
<pre><code class="hljs basic"><span class="hljs-symbol">0 </span><span class="hljs-number">1</span> <span class="hljs-number">0</span> <span class="hljs-number">0</span> <span class="hljs-number">1</span> 
<span class="hljs-symbol">1 </span><span class="hljs-number">0</span> <span class="hljs-number">1</span> <span class="hljs-number">1</span> <span class="hljs-number">0</span> 
<span class="hljs-symbol">0 </span><span class="hljs-number">1</span> <span class="hljs-number">0</span> <span class="hljs-number">0</span> <span class="hljs-number">0</span> 
<span class="hljs-symbol">0 </span><span class="hljs-number">1</span> <span class="hljs-number">0</span> <span class="hljs-number">0</span> <span class="hljs-number">1</span> 
<span class="hljs-symbol">1 </span><span class="hljs-number">0</span> <span class="hljs-number">0</span> <span class="hljs-number">1</span> <span class="hljs-number">0</span></code></pre>

<p>其中0表示没有连接，1表示有连接</p>
<h4 id="邻接表"><a href="#邻接表" class="headerlink" title="邻接表"></a>邻接表</h4><ul>
<li>邻接矩阵需要为每个顶点都分配 n个边的空间，其实有很多边都是不存在,<strong>会造成空间的一定损失</strong></li>
<li>邻接表的实现只关心存在的边，不关心不存在的边。因此没有空间浪费，<strong>邻接表由数组+链表组成</strong><ul>
<li>数组的索引代表顶点</li>
<li>链表中元素的值代表与该顶点相连的顶点的值</li>
</ul>
</li>
</ul>
<p>如上图的进阶表就是</p>
<p><img src="https://nyimapicture.oss-cn-beijing.aliyuncs.com/img/20200731154231.png" srcset="/img/loading.gif" alt=""></p>
<h2 id="2、图的创建"><a href="#2、图的创建" class="headerlink" title="2、图的创建"></a>2、图的创建</h2><h3 id="邻接矩阵创建图"><a href="#邻接矩阵创建图" class="headerlink" title="邻接矩阵创建图"></a>邻接矩阵创建图</h3><pre><code class="hljs java"><span class="hljs-keyword">public</span> <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">Demo2</span> </span>&#123;
   <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">static</span> <span class="hljs-keyword">void</span> <span class="hljs-title">main</span><span class="hljs-params">(String[] args)</span> </span>&#123;
      <span class="hljs-keyword">int</span> sum = <span class="hljs-number">5</span>;
      String[] vertex = &#123;<span class="hljs-string">"A"</span>, <span class="hljs-string">"B"</span>, <span class="hljs-string">"C"</span>, <span class="hljs-string">"D"</span>, <span class="hljs-string">"E"</span>&#125;;
      Graph graph = <span class="hljs-keyword">new</span> Graph(sum);
      <span class="hljs-comment">//指明图的顶点</span>
      <span class="hljs-keyword">for</span>(String top : vertex) &#123;
         graph.insertVertex(top);
      &#125;
      <span class="hljs-comment">//指明相连的顶点</span>
      graph.insertEdge(<span class="hljs-number">0</span>, <span class="hljs-number">1</span>, <span class="hljs-number">1</span>);
      graph.insertEdge(<span class="hljs-number">0</span>, <span class="hljs-number">2</span>, <span class="hljs-number">1</span>);
      graph.insertEdge(<span class="hljs-number">1</span>, <span class="hljs-number">2</span>, <span class="hljs-number">1</span>);
      graph.insertEdge(<span class="hljs-number">1</span>, <span class="hljs-number">3</span>, <span class="hljs-number">1</span>);
      graph.insertEdge(<span class="hljs-number">1</span>, <span class="hljs-number">4</span>, <span class="hljs-number">1</span>);

      <span class="hljs-comment">//显示邻接矩阵</span>
      System.out.println(<span class="hljs-string">"邻接矩阵"</span>);
      graph.showGraph();
   &#125;
&#125;

<span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">Graph</span> </span>&#123;
   ArrayList&lt;String&gt; vertexList;
   <span class="hljs-keyword">int</span>[][] edges;
   <span class="hljs-keyword">int</span> numOfEdges;

   <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-title">Graph</span><span class="hljs-params">(<span class="hljs-keyword">int</span> sum)</span> </span>&#123;
      <span class="hljs-comment">//根据顶点总数进行初始化</span>
      vertexList = <span class="hljs-keyword">new</span> ArrayList&lt;&gt;(sum);
      edges = <span class="hljs-keyword">new</span> <span class="hljs-keyword">int</span>[sum][sum];
      numOfEdges = <span class="hljs-number">0</span>;
   &#125;

   <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">insertVertex</span><span class="hljs-params">(String vertex)</span> </span>&#123;
      vertexList.add(vertex);
   &#125;

   <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">insertEdge</span><span class="hljs-params">(<span class="hljs-keyword">int</span> vertex1, <span class="hljs-keyword">int</span> vertex2, <span class="hljs-keyword">int</span> weight)</span> </span>&#123;
      edges[vertex1][vertex2] = weight;
      edges[vertex2][vertex1] = weight;
      numOfEdges++;
   &#125;

   <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">int</span> <span class="hljs-title">getNumOfEdges</span><span class="hljs-params">()</span> </span>&#123;
      <span class="hljs-keyword">return</span> numOfEdges;
   &#125;

   <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">int</span> <span class="hljs-title">getNumOfVertex</span><span class="hljs-params">()</span> </span>&#123;
      <span class="hljs-keyword">return</span> vertexList.size();
   &#125;

   <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">int</span> <span class="hljs-title">getWeight</span><span class="hljs-params">(<span class="hljs-keyword">int</span> vertex1, <span class="hljs-keyword">int</span> vertex2)</span> </span>&#123;
      <span class="hljs-keyword">return</span> edges[vertex1][vertex2];
   &#125;

   <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">showGraph</span><span class="hljs-params">()</span> </span>&#123;
      <span class="hljs-keyword">for</span>(<span class="hljs-keyword">int</span>[] list : edges) &#123;
         System.out.println(Arrays.toString(list));
      &#125;
   &#125;
&#125;</code></pre>



<p><strong>运行结果</strong></p>
<pre><code class="hljs json">[<span class="hljs-number">0</span>, <span class="hljs-number">1</span>, <span class="hljs-number">1</span>, <span class="hljs-number">0</span>, <span class="hljs-number">0</span>]
[<span class="hljs-number">1</span>, <span class="hljs-number">0</span>, <span class="hljs-number">1</span>, <span class="hljs-number">1</span>, <span class="hljs-number">1</span>]
[<span class="hljs-number">1</span>, <span class="hljs-number">1</span>, <span class="hljs-number">0</span>, <span class="hljs-number">0</span>, <span class="hljs-number">0</span>]
[<span class="hljs-number">0</span>, <span class="hljs-number">1</span>, <span class="hljs-number">0</span>, <span class="hljs-number">0</span>, <span class="hljs-number">0</span>]
[<span class="hljs-number">0</span>, <span class="hljs-number">1</span>, <span class="hljs-number">0</span>, <span class="hljs-number">0</span>, <span class="hljs-number">0</span>]</code></pre>



<h2 id="3、图的遍历"><a href="#3、图的遍历" class="headerlink" title="3、图的遍历"></a>3、图的遍历</h2><p>对该图进行深度优先遍历和广度优先遍历</p>
<p><img src="https://nyimapicture.oss-cn-beijing.aliyuncs.com/img/20200801122515.png" srcset="/img/loading.gif" alt=""></p>
<h3 id="深度优先遍历（DFS）"><a href="#深度优先遍历（DFS）" class="headerlink" title="深度优先遍历（DFS）"></a>深度优先遍历（DFS）</h3><ul>
<li>深度优先遍历，从初始访问结点出发，初始访问结点可能有多个邻接结点，深度优先遍历的策略就是首先访问第一个邻接结点，然后再以这个被访问的邻接结点作为初始结点，访问它的第一个邻接结点，可以这样理解：每次都在访问完当前结点后首先访问当前结点的第一个邻接结点。</li>
<li>这样的访问策略是<strong>优先往纵向挖掘深入</strong></li>
<li>深度优先搜索是一个递归的过程</li>
</ul>
<h4 id="思路"><a href="#思路" class="headerlink" title="思路"></a>思路</h4><ul>
<li>访问初始结点v，并标记结点v为已访问</li>
<li>查找结点v的第一个邻接结点w</li>
<li>若w存在，则继续执行4，如果w不存在，则回到第1步，将从v的下一个结点继续</li>
<li>若w未被访问，对w进行深度优先遍历递归（即把w当做另一个v，然后进行步骤123）</li>
<li>查找结点v的w邻接结点的下一个邻接结点，转到步骤 3</li>
</ul>
<h4 id="实现代码-8"><a href="#实现代码-8" class="headerlink" title="实现代码"></a>实现代码</h4><pre><code class="hljs java"><span class="hljs-keyword">public</span> <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">Demo2</span> </span>&#123;
	<span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">static</span> <span class="hljs-keyword">void</span> <span class="hljs-title">main</span><span class="hljs-params">(String[] args)</span> </span>&#123;
		<span class="hljs-keyword">int</span> sum = <span class="hljs-number">5</span>;
		String[] vertex = &#123;<span class="hljs-string">"A"</span>, <span class="hljs-string">"B"</span>, <span class="hljs-string">"C"</span>, <span class="hljs-string">"D"</span>, <span class="hljs-string">"E"</span>&#125;;
		Graph graph = <span class="hljs-keyword">new</span> Graph(sum);
		<span class="hljs-comment">//指明图的顶点</span>
		<span class="hljs-keyword">for</span>(String top : vertex) &#123;
			graph.insertVertex(top);
		&#125;
		<span class="hljs-comment">//指明相连的顶点</span>
		graph.insertEdge(<span class="hljs-number">0</span>, <span class="hljs-number">1</span>, <span class="hljs-number">1</span>);
		graph.insertEdge(<span class="hljs-number">0</span>, <span class="hljs-number">2</span>, <span class="hljs-number">1</span>);
		graph.insertEdge(<span class="hljs-number">0</span>, <span class="hljs-number">3</span>, <span class="hljs-number">1</span>);
		graph.insertEdge(<span class="hljs-number">1</span>, <span class="hljs-number">2</span>, <span class="hljs-number">1</span>);
		graph.insertEdge(<span class="hljs-number">1</span>, <span class="hljs-number">4</span>, <span class="hljs-number">1</span>);
		<span class="hljs-comment">//显示邻接矩阵</span>
		System.out.println(<span class="hljs-string">"邻接矩阵"</span>);
		graph.showGraph();
		<span class="hljs-comment">//深度优先遍历</span>
		System.out.println(<span class="hljs-string">"进行深度优先遍历"</span>);
		graph.dfs();
	&#125;
&#125;

<span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">Graph</span> </span>&#123;
	<span class="hljs-keyword">private</span> ArrayList&lt;String&gt; vertexList;
	<span class="hljs-keyword">private</span> <span class="hljs-keyword">int</span>[][] edges;
	<span class="hljs-keyword">private</span> <span class="hljs-keyword">int</span> numOfEdges;
	<span class="hljs-comment">/**</span>
<span class="hljs-comment">	 * 标记是否访问过该顶点，用于遍历</span>
<span class="hljs-comment">	 */</span>
	<span class="hljs-keyword">private</span> <span class="hljs-keyword">boolean</span>[] isTraversed;

	<span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-title">Graph</span><span class="hljs-params">(<span class="hljs-keyword">int</span> sum)</span> </span>&#123;
		<span class="hljs-comment">//根据顶点总数进行初始化</span>
		vertexList = <span class="hljs-keyword">new</span> ArrayList&lt;&gt;(sum);
		edges = <span class="hljs-keyword">new</span> <span class="hljs-keyword">int</span>[sum][sum];
		isTraversed = <span class="hljs-keyword">new</span> <span class="hljs-keyword">boolean</span>[sum];
		numOfEdges = <span class="hljs-number">0</span>;
	&#125;

	<span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">insertVertex</span><span class="hljs-params">(String vertex)</span> </span>&#123;
		vertexList.add(vertex);
	&#125;

	<span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">insertEdge</span><span class="hljs-params">(<span class="hljs-keyword">int</span> vertex1, <span class="hljs-keyword">int</span> vertex2, <span class="hljs-keyword">int</span> weight)</span> </span>&#123;
		edges[vertex1][vertex2] = weight;
		edges[vertex2][vertex1] = weight;
		numOfEdges++;
	&#125;

	<span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">showGraph</span><span class="hljs-params">()</span> </span>&#123;
		<span class="hljs-keyword">for</span>(<span class="hljs-keyword">int</span>[] list : edges) &#123;
			System.out.println(Arrays.toString(list));
		&#125;
	&#125;
	
	<span class="hljs-comment">/**</span>
<span class="hljs-comment">	 * 深度优先遍历</span>
<span class="hljs-comment">	 * <span class="hljs-doctag">@param</span> vertex 开始顶点下标</span>
<span class="hljs-comment">	 */</span>
	<span class="hljs-function"><span class="hljs-keyword">private</span> <span class="hljs-keyword">void</span> <span class="hljs-title">dfs</span><span class="hljs-params">(<span class="hljs-keyword">int</span> vertex)</span> </span>&#123;
		<span class="hljs-comment">//被访问过了就返回</span>
		<span class="hljs-keyword">if</span>(isTraversed[vertex]) &#123;
			<span class="hljs-keyword">return</span>;
		&#125;
		System.out.print(vertexList.get(vertex) + <span class="hljs-string">"-&gt;"</span>);
		<span class="hljs-comment">//标记已被访问</span>
		isTraversed[vertex] = <span class="hljs-keyword">true</span>;
		<span class="hljs-comment">//从相邻顶点开始深度优先遍历</span>
		<span class="hljs-keyword">for</span>(<span class="hljs-keyword">int</span> nextVertex = vertex+<span class="hljs-number">1</span>; nextVertex&lt;vertexList.size(); nextVertex++) &#123;
			<span class="hljs-comment">//如果该顶点存在且未被访问，就向下访问</span>
			<span class="hljs-keyword">if</span>(edges[vertex][nextVertex] != <span class="hljs-number">0</span> &amp;&amp; !isTraversed[nextVertex] ) &#123;
				dfs(nextVertex);
			&#125;
		&#125;
	&#125;

	<span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">dfs</span><span class="hljs-params">()</span> </span>&#123;
		<span class="hljs-comment">//对未被访问的顶点都进行深度优先遍历</span>
		<span class="hljs-keyword">for</span>(<span class="hljs-keyword">int</span> i = <span class="hljs-number">0</span>; i&lt;vertexList.size(); i++) &#123;
			<span class="hljs-keyword">if</span>(!isTraversed[i]) &#123;
				dfs(i);
			&#125;
		&#125;
	&#125;
&#125;</code></pre>



<p><strong>运行结果</strong></p>
<pre><code class="hljs angelscript">邻接矩阵
[<span class="hljs-number">0</span>, <span class="hljs-number">1</span>, <span class="hljs-number">1</span>, <span class="hljs-number">0</span>, <span class="hljs-number">0</span>]
[<span class="hljs-number">1</span>, <span class="hljs-number">0</span>, <span class="hljs-number">1</span>, <span class="hljs-number">1</span>, <span class="hljs-number">1</span>]
[<span class="hljs-number">1</span>, <span class="hljs-number">1</span>, <span class="hljs-number">0</span>, <span class="hljs-number">0</span>, <span class="hljs-number">0</span>]
[<span class="hljs-number">0</span>, <span class="hljs-number">1</span>, <span class="hljs-number">0</span>, <span class="hljs-number">0</span>, <span class="hljs-number">0</span>]
[<span class="hljs-number">0</span>, <span class="hljs-number">1</span>, <span class="hljs-number">0</span>, <span class="hljs-number">0</span>, <span class="hljs-number">0</span>]
进行深度优先遍历
A-&gt;B-&gt;C-&gt;E-&gt;D-&gt;</code></pre>



<h3 id="广度优先遍历（BFS）"><a href="#广度优先遍历（BFS）" class="headerlink" title="广度优先遍历（BFS）"></a>广度优先遍历（BFS）</h3><ul>
<li>类似于一个<strong>分层搜索</strong>的过程，广度优先遍历需要使用一个<strong>队列</strong>以保持访问过的结点的顺序，以便按这个顺序来访问这些结点的邻接结点</li>
</ul>
<h4 id="思路-1"><a href="#思路-1" class="headerlink" title="思路"></a>思路</h4><ul>
<li>访问初始结点 v并标记结点 v为已访问</li>
<li>结点v入队列</li>
<li>当队列非空时，继续执行，否则算法结束</li>
<li>出队列，取得队头结点u</li>
<li>查找结点 u的第一个邻接结点 w。</li>
<li>若结点 u的邻接结点 w不存在，则转到步骤 3；否则循环执行以下三个步骤：<ul>
<li>若结点 w尚未被访问，则访问结点 w并标记为已访问</li>
<li>结点 w入队列</li>
<li>查找结点 u的继 w邻接结点后的下一个邻接结点 w，转到步骤6</li>
</ul>
</li>
</ul>
<h4 id="实现代码-9"><a href="#实现代码-9" class="headerlink" title="实现代码"></a>实现代码</h4><pre><code class="hljs java"><span class="hljs-keyword">public</span> <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">Demo2</span> </span>&#123;
   <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">static</span> <span class="hljs-keyword">void</span> <span class="hljs-title">main</span><span class="hljs-params">(String[] args)</span> </span>&#123;
      <span class="hljs-keyword">int</span> sum = <span class="hljs-number">5</span>;
      String[] vertex = &#123;<span class="hljs-string">"A"</span>, <span class="hljs-string">"B"</span>, <span class="hljs-string">"C"</span>, <span class="hljs-string">"D"</span>, <span class="hljs-string">"E"</span>&#125;;
      Graph graph = <span class="hljs-keyword">new</span> Graph(sum);
      <span class="hljs-comment">//指明图的顶点</span>
      <span class="hljs-keyword">for</span>(String top : vertex) &#123;
         graph.insertVertex(top);
      &#125;
      <span class="hljs-comment">//指明相连的顶点</span>
      graph.insertEdge(<span class="hljs-number">0</span>, <span class="hljs-number">1</span>, <span class="hljs-number">1</span>);
      graph.insertEdge(<span class="hljs-number">0</span>, <span class="hljs-number">2</span>, <span class="hljs-number">1</span>);
      graph.insertEdge(<span class="hljs-number">0</span>, <span class="hljs-number">3</span>, <span class="hljs-number">1</span>);
      graph.insertEdge(<span class="hljs-number">1</span>, <span class="hljs-number">2</span>, <span class="hljs-number">1</span>);
      graph.insertEdge(<span class="hljs-number">1</span>, <span class="hljs-number">4</span>, <span class="hljs-number">1</span>);
      <span class="hljs-comment">//显示邻接矩阵</span>
      System.out.println(<span class="hljs-string">"邻接矩阵"</span>);
      graph.showGraph();
      <span class="hljs-comment">//广度优先遍历</span>
      System.out.println(<span class="hljs-string">"进行广度优先遍历"</span>);
      graph.bfs();
   &#125;
&#125;

<span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">Graph</span> </span>&#123;
   <span class="hljs-keyword">private</span> ArrayList&lt;String&gt; vertexList;
   <span class="hljs-keyword">private</span> <span class="hljs-keyword">int</span>[][] edges;
   <span class="hljs-keyword">private</span> <span class="hljs-keyword">int</span> numOfEdges;
   <span class="hljs-comment">/**</span>
<span class="hljs-comment">    * 标记是否访问过该顶点，用于遍历</span>
<span class="hljs-comment">    */</span>
   <span class="hljs-keyword">private</span> <span class="hljs-keyword">boolean</span>[] isTraversed;
   <span class="hljs-comment">/**</span>
<span class="hljs-comment">    * 用于保存访问过的顶点</span>
<span class="hljs-comment">    */</span>
   <span class="hljs-keyword">private</span> Queue&lt;Integer&gt; queue;

   <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-title">Graph</span><span class="hljs-params">(<span class="hljs-keyword">int</span> sum)</span> </span>&#123;
      <span class="hljs-comment">//根据顶点总数进行初始化</span>
      vertexList = <span class="hljs-keyword">new</span> ArrayList&lt;&gt;(sum);
      edges = <span class="hljs-keyword">new</span> <span class="hljs-keyword">int</span>[sum][sum];
      isTraversed = <span class="hljs-keyword">new</span> <span class="hljs-keyword">boolean</span>[sum];
      numOfEdges = <span class="hljs-number">0</span>;
      queue = <span class="hljs-keyword">new</span> LinkedList&lt;Integer&gt;();
   &#125;

   <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">insertVertex</span><span class="hljs-params">(String vertex)</span> </span>&#123;
      vertexList.add(vertex);
   &#125;

   <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">insertEdge</span><span class="hljs-params">(<span class="hljs-keyword">int</span> vertex1, <span class="hljs-keyword">int</span> vertex2, <span class="hljs-keyword">int</span> weight)</span> </span>&#123;
      edges[vertex1][vertex2] = weight;
      edges[vertex2][vertex1] = weight;
      numOfEdges++;
   &#125;

   <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">showGraph</span><span class="hljs-params">()</span> </span>&#123;
      <span class="hljs-keyword">for</span>(<span class="hljs-keyword">int</span>[] list : edges) &#123;
         System.out.println(Arrays.toString(list));
      &#125;
   &#125;

   <span class="hljs-comment">/**</span>
<span class="hljs-comment">    * 广度优先遍历</span>
<span class="hljs-comment">    *</span>
<span class="hljs-comment">    * <span class="hljs-doctag">@param</span> vertex 遍历顶点的下标</span>
<span class="hljs-comment">    */</span>
   <span class="hljs-function"><span class="hljs-keyword">private</span> <span class="hljs-keyword">void</span> <span class="hljs-title">bfs</span><span class="hljs-params">(<span class="hljs-keyword">int</span> vertex)</span> </span>&#123;
      <span class="hljs-comment">//未被访问，打印顶点信息</span>
      <span class="hljs-keyword">if</span>(!isTraversed[vertex]) &#123;
         System.out.print(vertexList.get(vertex) + <span class="hljs-string">"-&gt;"</span>);
         isTraversed[vertex] = <span class="hljs-keyword">true</span>;
      &#125;
      <span class="hljs-comment">//继续访问相邻元素</span>
      <span class="hljs-keyword">for</span>(<span class="hljs-keyword">int</span> nextVertex = vertex+<span class="hljs-number">1</span>; nextVertex &lt; vertexList.size(); nextVertex++) &#123;
         <span class="hljs-comment">//如果存在且未被访问</span>
         <span class="hljs-keyword">if</span>(edges[vertex][nextVertex] != <span class="hljs-number">0</span> &amp;&amp; !isTraversed[nextVertex]) &#123;
            <span class="hljs-comment">//打印顶点信息</span>
            System.out.print(vertexList.get(nextVertex) + <span class="hljs-string">"-&gt;"</span>);
            <span class="hljs-comment">//标记为已访问</span>
            isTraversed[nextVertex] = <span class="hljs-keyword">true</span>;
            <span class="hljs-comment">//入队</span>
            queue.add(nextVertex);
         &#125;
      &#125;
      <span class="hljs-comment">//相邻元素访问完了（广度优先），再让队列中的元素出队，继续访问</span>
      <span class="hljs-keyword">while</span> (!queue.isEmpty()) &#123;
         <span class="hljs-comment">//队首元素出队，继续访问</span>
         bfs(queue.remove());
      &#125;
   &#125;

   <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">bfs</span><span class="hljs-params">()</span> </span>&#123;
      <span class="hljs-keyword">for</span>(<span class="hljs-keyword">int</span> i = <span class="hljs-number">0</span>; i&lt;vertexList.size(); i++) &#123;
         <span class="hljs-comment">//未被访问过，就进行广度优先遍历</span>
         <span class="hljs-keyword">if</span>(!isTraversed[i]) &#123;
            bfs(i);
         &#125;
      &#125;
   &#125;
&#125;</code></pre>



<p><strong>运行结果</strong></p>
<pre><code class="hljs java">邻接矩阵
[<span class="hljs-number">0</span>, <span class="hljs-number">1</span>, <span class="hljs-number">1</span>, <span class="hljs-number">1</span>, <span class="hljs-number">0</span>]
[<span class="hljs-number">1</span>, <span class="hljs-number">0</span>, <span class="hljs-number">1</span>, <span class="hljs-number">0</span>, <span class="hljs-number">1</span>]
[<span class="hljs-number">1</span>, <span class="hljs-number">1</span>, <span class="hljs-number">0</span>, <span class="hljs-number">0</span>, <span class="hljs-number">0</span>]
[<span class="hljs-number">1</span>, <span class="hljs-number">0</span>, <span class="hljs-number">0</span>, <span class="hljs-number">0</span>, <span class="hljs-number">0</span>]
[<span class="hljs-number">0</span>, <span class="hljs-number">1</span>, <span class="hljs-number">0</span>, <span class="hljs-number">0</span>, <span class="hljs-number">0</span>]
进行广度优先遍历
A-&gt;B-&gt;C-&gt;D-&gt;E-&gt;</code></pre>



<h1 id="十、算法"><a href="#十、算法" class="headerlink" title="十、算法"></a>十、算法</h1><h2 id="1、分治算法"><a href="#1、分治算法" class="headerlink" title="1、分治算法"></a>1、分治算法</h2><h3 id="算法介绍"><a href="#算法介绍" class="headerlink" title="算法介绍"></a>算法介绍</h3><p>分治法是一种很重要的算法。字面上的解释是“分而治之”，就是<strong>把一个复杂的问题分成两个或更多的相同或相似的子问题，再把子问题分成更小的子问题……直到最后子问题可以简单的直接求解，原问题的解即子问题的解的合并</strong>。这个技巧是很多高效算法的基础，如排序算法(快速排序，归并排序)，傅立叶变换(快速傅立叶变换)……</p>
<h3 id="基本步骤"><a href="#基本步骤" class="headerlink" title="基本步骤"></a>基本步骤</h3><p><strong>分治法在每一层递归上都有三个步骤</strong>：</p>
<ul>
<li>分解：将原问题分解为若干个规模较小，相互独立，与原问题形式相同的子问题</li>
<li>解决：若子问题规模较小而容易被解决则直接解，否则递归地解各个子问题</li>
<li>合并：将各个子问题的解合并为原问题的解</li>
</ul>
<h3 id="应用——汉诺塔"><a href="#应用——汉诺塔" class="headerlink" title="应用——汉诺塔"></a>应用——汉诺塔</h3><h4 id="思路-2"><a href="#思路-2" class="headerlink" title="思路"></a>思路</h4><p>A、B、C三个塔</p>
<ul>
<li>如果只有一个盘，直接A-&gt;C</li>
<li>如果大于等于两个盘，就分成两部分。<strong>最下面的一个盘为一部分，上面的所有盘为一部分</strong><ul>
<li>将上面部分的盘A-&gt;B</li>
<li>最下面的盘A-&gt;C</li>
<li>再将B中的盘B-&gt;C</li>
</ul>
</li>
</ul>
<h4 id="实现代码-10"><a href="#实现代码-10" class="headerlink" title="实现代码"></a>实现代码</h4><pre><code class="hljs java"><span class="hljs-keyword">public</span> <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">Demo1</span> </span>&#123;
   <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">static</span> <span class="hljs-keyword">void</span> <span class="hljs-title">main</span><span class="hljs-params">(String[] args)</span> </span>&#123;
      hanoiTower(<span class="hljs-number">3</span>, <span class="hljs-string">'A'</span>, <span class="hljs-string">'B'</span>, <span class="hljs-string">'C'</span>);
   &#125;

   <span class="hljs-comment">/**</span>
<span class="hljs-comment">    * 汉诺塔</span>
<span class="hljs-comment">    *</span>
<span class="hljs-comment">    * <span class="hljs-doctag">@param</span> num 盘的总数</span>
<span class="hljs-comment">    * <span class="hljs-doctag">@param</span> a 第一个塔</span>
<span class="hljs-comment">    * <span class="hljs-doctag">@param</span> b 第二个塔</span>
<span class="hljs-comment">    * <span class="hljs-doctag">@param</span> c 第三个塔</span>
<span class="hljs-comment">    */</span>
   <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">static</span> <span class="hljs-keyword">void</span> <span class="hljs-title">hanoiTower</span><span class="hljs-params">(<span class="hljs-keyword">int</span> num, <span class="hljs-keyword">char</span> a, <span class="hljs-keyword">char</span> b, <span class="hljs-keyword">char</span> c)</span> </span>&#123;
      <span class="hljs-comment">//如果只有一个盘，把这个盘从A移动到C</span>
      <span class="hljs-keyword">if</span>(num == <span class="hljs-number">1</span>) &#123;
         System.out.println(<span class="hljs-string">"把第"</span> + num + <span class="hljs-string">"个盘从"</span> + a + <span class="hljs-string">"-&gt;"</span> + c);
         <span class="hljs-keyword">return</span>;
      &#125;
      <span class="hljs-comment">//如果大于等于两个盘，将上面部分的盘从A借助C移动到B</span>
      hanoiTower(num-<span class="hljs-number">1</span>, a, c, b);
      <span class="hljs-comment">//把最下面的盘从A移动到C</span>
      System.out.println(<span class="hljs-string">"把第"</span> + num + <span class="hljs-string">"个盘从"</span> + a + <span class="hljs-string">"-&gt;"</span> + c);
      <span class="hljs-comment">//把上面部分的盘从B借助A移动到C</span>
      hanoiTower(num-<span class="hljs-number">1</span>, b, a, c);
   &#125;
&#125;</code></pre>



<p><strong>运行结果</strong></p>
<pre><code class="hljs angelscript">把第<span class="hljs-number">1</span>个盘从A-&gt;C
把第<span class="hljs-number">2</span>个盘从A-&gt;B
把第<span class="hljs-number">1</span>个盘从C-&gt;B
把第<span class="hljs-number">3</span>个盘从A-&gt;C
把第<span class="hljs-number">1</span>个盘从B-&gt;A
把第<span class="hljs-number">2</span>个盘从B-&gt;C
把第<span class="hljs-number">1</span>个盘从A-&gt;C</code></pre>



<h3 id="博客推荐"><a href="#博客推荐" class="headerlink" title="博客推荐"></a>博客推荐</h3><p>在刷leetcode时有幸看到了一位大佬写的关于递归的博客，在此转载贴出。</p>
<p><a href="https://lyl0724.github.io/2020/01/25/1/" target="_blank" rel="noopener">点此跳转</a></p>
<h2 id="2、动态规划"><a href="#2、动态规划" class="headerlink" title="2、动态规划"></a>2、动态规划</h2><h3 id="算法介绍-1"><a href="#算法介绍-1" class="headerlink" title="算法介绍"></a>算法介绍</h3><ul>
<li>动态规划(Dynamic Programming)算法的核心思想是：将<strong>大问题划分为小问题</strong>进行解决，从而一步步获取最优解的处理算法</li>
<li>动态规划算法与分治算法类似，其基本思想也是将待求解问题分解成若干个子问题，先求解子问题，然后从这些子问题的解得到原问题的解</li>
<li>与分治法不同的是，适合于用动态规划求解的问题，经分解得到<strong>子问题往往不是互相独立的</strong>。( 即下一个子阶段的求解是建立在上一个子阶段的解的基础上，进行进一步的求解 )</li>
<li>动态规划可以通过<strong>填表</strong>的方式来逐步推进，得到最优解</li>
</ul>
<h3 id="算法应用——01背包问题"><a href="#算法应用——01背包问题" class="headerlink" title="算法应用——01背包问题"></a>算法应用——01背包问题</h3><table>
<thead>
<tr>
<th align="center">物品</th>
<th align="center">重量</th>
<th align="center">价值</th>
</tr>
</thead>
<tbody><tr>
<td align="center">吉他</td>
<td align="center">1</td>
<td align="center">1500</td>
</tr>
<tr>
<td align="center">音响</td>
<td align="center">4</td>
<td align="center">3000</td>
</tr>
<tr>
<td align="center">电脑</td>
<td align="center">3</td>
<td align="center">2000</td>
</tr>
</tbody></table>
<p>一个背包最多装4kg的东西，求</p>
<ul>
<li>装入物品使得背包的总价值最大，且不超出背包的容量</li>
<li>要求装入的物品<strong>不能重复</strong>（01背包）</li>
</ul>
<h4 id="解题思路"><a href="#解题思路" class="headerlink" title="解题思路"></a>解题思路</h4><p>算法的主要思想，利用动态规划来解决。每次遍历到的第 i个物品，根据 w[i]和 v[i]来确定是否需要将该物品放入背包中。即对于给定的 n个物品，<strong>设 v[i]、w[i]分别为第 i个物品的价值和重量</strong>，C为背包的容量。再令二维数组</p>
<pre><code class="hljs markdown">v[<span class="hljs-string">i</span>][<span class="hljs-symbol">j</span>]</code></pre>

<p>表示在前 i个物品中能够装入容量为 j的背包中的<strong>最大价值</strong>。则我们有下面的结果</p>
<pre><code class="hljs java"><span class="hljs-comment">//表示填入表的第一行和第一列是 0，主要是为了方便表示物品和容量</span>
(<span class="hljs-number">1</span>) v[i][<span class="hljs-number">0</span>]=v[<span class="hljs-number">0</span>][j]=<span class="hljs-number">0</span>; 

<span class="hljs-comment">// 当准备加入新增的商品的重量大于当前背包的容量时，就直接使用上一个单元格的装入策略（装入物品的价值）</span>
(<span class="hljs-number">2</span>) 当 w[i]&gt;j 时：v[i][j]=v[i-<span class="hljs-number">1</span>][j] 

<span class="hljs-comment">// 当准备加入的新增的商品的容量小于等于当前背包的容量,</span>
<span class="hljs-comment">// 装入的方式:</span>
(<span class="hljs-number">3</span>) 当 j&gt;=w[i]时：v[i][j]=max&#123;v[i-<span class="hljs-number">1</span>][j], v[i]+v[i-<span class="hljs-number">1</span>][j-w[i]]&#125;

v[i-<span class="hljs-number">1</span>][j]：上一个装法的总价值

v[i] : 表示当前商品的价值

v[i-<span class="hljs-number">1</span>][j-w[i]] ： 装入i-<span class="hljs-number">1</span>商品，到剩余空间j-w[i]的总价值</code></pre>

<p>简单来说：</p>
<ul>
<li><p>装入物品的容量大于背包容量时，直接使用之前装入背包物品的最大价值</p>
</li>
<li><p>装入物品容量小于等于背包容量时，比较</p>
<ul>
<li>装入该物品之前，背包物品的最大价值</li>
<li>装入该后，该物品的价值+剩余容量能放入物品的最大价值</li>
</ul>
<p>选取较大者</p>
</li>
</ul>
<h4 id="实现代码-11"><a href="#实现代码-11" class="headerlink" title="实现代码"></a>实现代码</h4><pre><code class="hljs java"><span class="hljs-keyword">public</span> <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">Demo2</span> </span>&#123;
   <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">static</span> <span class="hljs-keyword">void</span> <span class="hljs-title">main</span><span class="hljs-params">(String[] args)</span> </span>&#123;
      <span class="hljs-comment">//各个物品的重量</span>
      <span class="hljs-keyword">int</span>[] weight = &#123;<span class="hljs-number">1</span>, <span class="hljs-number">4</span>, <span class="hljs-number">3</span>&#125;;
      <span class="hljs-comment">//各个物品的价值</span>
      <span class="hljs-keyword">int</span>[] value = &#123;<span class="hljs-number">1500</span>, <span class="hljs-number">3000</span>, <span class="hljs-number">2000</span>&#125;;
      <span class="hljs-comment">//背包的最大容量</span>
      <span class="hljs-keyword">int</span> maxSize = <span class="hljs-number">4</span>;
      <span class="hljs-comment">//各种方法的价值的最大值，第0行和第0列值为0，方便后续操作</span>
      <span class="hljs-keyword">int</span>[][] maxValue = <span class="hljs-keyword">new</span> <span class="hljs-keyword">int</span>[value.length+<span class="hljs-number">1</span>][maxSize+<span class="hljs-number">1</span>];
      <span class="hljs-comment">//用于表示物品放入背包的方式</span>
      <span class="hljs-keyword">int</span>[][] method = <span class="hljs-keyword">new</span> <span class="hljs-keyword">int</span>[value.length+<span class="hljs-number">1</span>][maxSize+<span class="hljs-number">1</span>];

      <span class="hljs-comment">//依次将物品放入背包</span>
      <span class="hljs-keyword">for</span>(<span class="hljs-keyword">int</span> i = <span class="hljs-number">1</span>; i&lt;maxValue.length; i++) &#123;
         <span class="hljs-keyword">for</span>(<span class="hljs-keyword">int</span> j = <span class="hljs-number">1</span>; j&lt;maxValue[<span class="hljs-number">0</span>].length; j++) &#123;
            <span class="hljs-comment">//如果物品的重量大于背包剩余的容量，就不放入</span>
            <span class="hljs-comment">//i-1是因为下标是从1开始的，减一后才为0</span>
            <span class="hljs-keyword">if</span>(weight[i-<span class="hljs-number">1</span>] &gt; j) &#123;
               maxValue[i][j] = maxValue[i-<span class="hljs-number">1</span>][j];
            &#125; <span class="hljs-keyword">else</span> &#123;
               <span class="hljs-comment">//背包剩余的容量</span>
               <span class="hljs-keyword">int</span> remaining = j - weight[i-<span class="hljs-number">1</span>];
               <span class="hljs-comment">//如果放入该物品前的最大价值大于放入该物品后的最大价值，就不放入该物品</span>
               <span class="hljs-keyword">if</span>(maxValue[i-<span class="hljs-number">1</span>][j] &gt; value[i-<span class="hljs-number">1</span>]+maxValue[i-<span class="hljs-number">1</span>][remaining]) &#123;
                  maxValue[i][j] = maxValue[i-<span class="hljs-number">1</span>][j];
               &#125; <span class="hljs-keyword">else</span> &#123;
                  maxValue[i][j] = value[i-<span class="hljs-number">1</span>]+maxValue[i-<span class="hljs-number">1</span>][remaining];
                  <span class="hljs-comment">//存入放入方法</span>
                  method[i][j] = <span class="hljs-number">1</span>;
               &#125;
            &#125;
         &#125;
      &#125;

      <span class="hljs-comment">//打印放入背包的最大价值</span>
      <span class="hljs-keyword">for</span>(<span class="hljs-keyword">int</span>[] arr : maxValue) &#123;
         System.out.println(Arrays.toString(arr));
      &#125;


      <span class="hljs-comment">//打印价值最大的放法</span>
      <span class="hljs-comment">//存放方法的二维数组的最大下标，从最后开始搜索存放方法</span>
      <span class="hljs-keyword">int</span> i = method.length - <span class="hljs-number">1</span>;
      <span class="hljs-keyword">int</span> j = method[<span class="hljs-number">0</span>].length - <span class="hljs-number">1</span>;
      <span class="hljs-keyword">while</span>(i &gt; <span class="hljs-number">0</span> &amp;&amp; j &gt; <span class="hljs-number">0</span>) &#123;
         <span class="hljs-keyword">if</span>(method[i][j] == <span class="hljs-number">1</span>) &#123;
            System.out.println(<span class="hljs-string">"将第"</span> + i + <span class="hljs-string">"个物品放入背包"</span>);
            <span class="hljs-comment">//背包剩余容量</span>
            j -= weight[i-<span class="hljs-number">1</span>];
         &#125;
         i--;
      &#125;
   &#125;
&#125;</code></pre>



<p><strong>运行结果</strong></p>
<pre><code class="hljs java">[<span class="hljs-number">0</span>, <span class="hljs-number">0</span>, <span class="hljs-number">0</span>, <span class="hljs-number">0</span>, <span class="hljs-number">0</span>]
[<span class="hljs-number">0</span>, <span class="hljs-number">1500</span>, <span class="hljs-number">1500</span>, <span class="hljs-number">1500</span>, <span class="hljs-number">1500</span>]
[<span class="hljs-number">0</span>, <span class="hljs-number">1500</span>, <span class="hljs-number">1500</span>, <span class="hljs-number">1500</span>, <span class="hljs-number">3000</span>]
[<span class="hljs-number">0</span>, <span class="hljs-number">1500</span>, <span class="hljs-number">1500</span>, <span class="hljs-number">2000</span>, <span class="hljs-number">3500</span>]

将第<span class="hljs-number">3</span>个物品放入背包
将第<span class="hljs-number">1</span>个物品放入背包</code></pre>



<h2 id="3、KMP算法"><a href="#3、KMP算法" class="headerlink" title="3、KMP算法"></a>3、KMP算法</h2><p>KMP是一个<strong>解决模式串在文本串是否出现过</strong>，如果出现过，找出最早出现的位置的经典算法</p>
<h3 id="算法应用——字符串匹配"><a href="#算法应用——字符串匹配" class="headerlink" title="算法应用——字符串匹配"></a>算法应用——字符串匹配</h3><h4 id="思路及图解"><a href="#思路及图解" class="headerlink" title="思路及图解"></a>思路及图解</h4><p><strong>问题：</strong>有一个字符串 str1= BBC ABCDAB ABCDABCDABDE，和一个子串 str2=ABCDABD。现在要判断 str1 是否含有 str2, 如果存在，就返回第一次出现的位置, 如果没有，则返回-1</p>
<h4 id="算法步骤"><a href="#算法步骤" class="headerlink" title="算法步骤"></a>算法步骤</h4><ul>
<li>首先，用 str1的第一个字符和 str2的<strong>第一个字符去比较，不符合，关键词向后移动一位</strong></li>
</ul>
<p><img src="https://nyimapicture.oss-cn-beijing.aliyuncs.com/img/20200803143823.png" srcset="/img/loading.gif" alt=""></p>
<ul>
<li>重复第一步，还是不符合，再后移</li>
</ul>
<p><img src="https://nyimapicture.oss-cn-beijing.aliyuncs.com/img/20200803143912.png" srcset="/img/loading.gif" alt=""></p>
<ul>
<li>一直重复，直到 Str1有一个字符与 Str2的<strong>第一个字符符合为止</strong></li>
</ul>
<p><img src="https://nyimapicture.oss-cn-beijing.aliyuncs.com/img/20200803143947.png" srcset="/img/loading.gif" alt=""></p>
<ul>
<li>接着比较字符串和搜索词的下一个字符，还是符合</li>
</ul>
<p><img src="https://nyimapicture.oss-cn-beijing.aliyuncs.com/img/20200803144059.png" srcset="/img/loading.gif" alt=""></p>
<ul>
<li>遇到 Str1有一个字符与 Str2对应的字符<strong>不符合</strong></li>
</ul>
<p><img src="https://nyimapicture.oss-cn-beijing.aliyuncs.com/img/20200803144203.png" srcset="/img/loading.gif" alt=""></p>
<p><strong>重要步骤</strong></p>
<ul>
<li><p>这时候，想到的是继续遍历 str1的下一个字符，重复第 1步。(其实是很不明智的，因为此时 BCD已经比较过了，<strong>没有必要再做重复的工作</strong>，一个基本事实是，当空格与D不匹配时，<strong>你其实知道前面六个字符是”ABCDAB”</strong></p>
<ul>
<li>KMP 算法的想法是：设法利用这个已知信息，不要把”搜索位置”移回已经比较过的位置，继续把它向后移，这样就提高了效率</li>
</ul>
</li>
<li><p>怎么做到把刚刚重复的步骤省略掉？可以对 str2计算出一张<a href="https://nyimac.gitee.io/2020/06/17/%E6%95%B0%E6%8D%AE%E7%BB%93%E6%9E%84%E4%B8%8E%E7%AE%97%E6%B3%95/#%E9%83%A8%E5%88%86%E5%8C%B9%E9%85%8D%E8%A1%A8%E7%9A%84%E7%94%9F%E6%88%90">部分匹配表</a>，这张表的产生在后面介绍</p>
<ul>
<li><p>str2的部分匹配表如下</p>
<table>
<thead>
<tr>
<th>搜索词</th>
<th>A</th>
<th>B</th>
<th>C</th>
<th>D</th>
<th>A</th>
<th>B</th>
<th>D</th>
</tr>
</thead>
<tbody><tr>
<td>部分匹配值</td>
<td>0</td>
<td>0</td>
<td>0</td>
<td>0</td>
<td>1</td>
<td>2</td>
<td>0</td>
</tr>
</tbody></table>
</li>
</ul>
</li>
</ul>
<ul>
<li><p>已知空格与 D不匹配时，前面六个字符”ABCDAB”是匹配的。查表可知，<strong>最后一个匹配字符B</strong>对应的<strong>部分匹配值为 2</strong>，因此按照下面的公式算出向后移动的位数：</p>
<ul>
<li><strong>移动位数 = 已匹配的字符数 - 对应的部分匹配值</strong></li>
<li>因为 6 - 2 等于 4，<strong>所以将搜索词向后移动 4 位</strong></li>
</ul>
</li>
</ul>
<p><img src="https://nyimapicture.oss-cn-beijing.aliyuncs.com/img/20200803144832.png" srcset="/img/loading.gif" alt=""></p>
<p><img src="https://nyimapicture.oss-cn-beijing.aliyuncs.com/img/20200803144853.png" srcset="/img/loading.gif" alt=""></p>
<ul>
<li><p>因为空格与Ｃ不匹配，搜索词还要继续往后移。这时，已匹配的字符数为 2（”AB”），对应的<strong>部分匹配值为0</strong>。</p>
<p>所以，移动位数 = 2 - 0，结果为 2，于是将<strong>搜索词向后移 2 位</strong></p>
</li>
</ul>
<p><img src="https://nyimapicture.oss-cn-beijing.aliyuncs.com/img/20200803145044.png" srcset="/img/loading.gif" alt=""></p>
<ul>
<li>因为空格与 A不匹配，继续后移一位</li>
</ul>
<p><img src="https://nyimapicture.oss-cn-beijing.aliyuncs.com/img/20200803145118.png" srcset="/img/loading.gif" alt=""></p>
<p><img src="https://nyimapicture.oss-cn-beijing.aliyuncs.com/img/20200803145137.png" srcset="/img/loading.gif" alt=""></p>
<ul>
<li>逐位比较，直到发现 C与 D不匹配。于是，移动位数 = 6 - 2，继续<strong>将搜索词向后移动 4 位</strong></li>
</ul>
<p><img src="https://nyimapicture.oss-cn-beijing.aliyuncs.com/img/20200803145251.png" srcset="/img/loading.gif" alt=""></p>
<ul>
<li>逐位比较，直到搜索词的最后一位，发现完全匹配，<strong>于是搜索完成</strong>。如果还要继续搜索（即找出全部匹配），移动位数 = 7 - 0，再将搜索词向后移动 7 位，这里就不再重复了</li>
</ul>
<p><img src="https://nyimapicture.oss-cn-beijing.aliyuncs.com/img/20200803145352.png" srcset="/img/loading.gif" alt=""></p>
<h4 id="部分匹配表的生成"><a href="#部分匹配表的生成" class="headerlink" title="部分匹配表的生成"></a>部分匹配表的生成</h4><p><strong>前缀与后缀</strong></p>
<ul>
<li>前缀：ABCD的前缀为[A, AB, ABC]</li>
<li>后缀：ABCD的后缀为[BCD, CD, D]</li>
</ul>
<p>部分匹配值”就是”前缀”和”后缀”的最长的共有元素的长度。以”ABCDABD”为例，</p>
<ul>
<li><p>”A”的前缀和后缀都为空集，共有元素的长度为 0；</p>
</li>
<li><p>”AB”的前缀为[A]，后缀为[B]，共有元素的长度为 0；</p>
</li>
<li><p>”ABC”的前缀为[A, AB]，后缀为[BC, C]，共有元素的长度 0；</p>
</li>
<li><p>”ABCD”的前缀为[A, AB, ABC]，后缀为[BCD, CD, D]，共有元素的长度为 0；</p>
</li>
<li><p>”ABCDA”的前缀为[<strong>A</strong>, AB, ABC, ABCD]，后缀为[BCDA, CDA, DA, <strong>A</strong>]，共有元素为”A”，<strong>长度为 1</strong>；</p>
</li>
<li><p>”ABCDAB”的前缀为[A, <strong>AB,</strong> ABC, ABCD, ABCDA]，后缀为[BCDAB, CDAB, DAB, <strong>AB</strong>, B]，共有元素为”AB”，<strong>长度为 2</strong>；</p>
</li>
<li><p>”ABCDABD”的前缀为[A, AB, ABC, ABCD, ABCDA, ABCDAB]，后缀为[BCDABD, CDABD, DABD, ABD, BD,D]，共有元素的长度为 0。</p>
</li>
</ul>
<p><img src="https://nyimapicture.oss-cn-beijing.aliyuncs.com/img/20200803184352.png" srcset="/img/loading.gif" alt=""></p>
<h4 id="实现代码-12"><a href="#实现代码-12" class="headerlink" title="实现代码"></a>实现代码</h4><pre><code class="hljs java"><span class="hljs-keyword">public</span> <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">Demo3</span> </span>&#123;
   <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">static</span> <span class="hljs-keyword">void</span> <span class="hljs-title">main</span><span class="hljs-params">(String[] args)</span> </span>&#123;
      String str1 = <span class="hljs-string">"BBC ABCDAB ABCDABCDABDE"</span>;
      String str2 = <span class="hljs-string">"ABCDABD"</span>;
		<span class="hljs-keyword">int</span> result = getPosition(str1, str2);
		<span class="hljs-keyword">if</span>(result != -<span class="hljs-number">1</span>) &#123;
			System.out.print(<span class="hljs-string">"匹配位置是：str1["</span>);
			System.out.println(result + <span class="hljs-string">"]"</span>);
		&#125; <span class="hljs-keyword">else</span> &#123;
			System.out.println(<span class="hljs-string">"匹配失败"</span>);
		&#125;
   &#125;

   <span class="hljs-comment">/**</span>
<span class="hljs-comment">    *得到匹配字符串的部分匹配表</span>
<span class="hljs-comment">    *</span>
<span class="hljs-comment">    * <span class="hljs-doctag">@param</span> matchStr 用于匹配的字符串</span>
<span class="hljs-comment">    * <span class="hljs-doctag">@return</span> 部分匹配表</span>
<span class="hljs-comment">    */</span>
   <span class="hljs-keyword">public</span> <span class="hljs-keyword">static</span> <span class="hljs-keyword">int</span>[] getTable(String matchStr) &#123;
      <span class="hljs-comment">//部分匹配值的数组</span>
      <span class="hljs-keyword">int</span>[] sectionTable = <span class="hljs-keyword">new</span> <span class="hljs-keyword">int</span>[matchStr.length()];
      <span class="hljs-comment">//匹配字符串的第一个元素没有前缀与后缀，部分匹配值为0</span>
      sectionTable[<span class="hljs-number">0</span>] = <span class="hljs-number">0</span>;
      <span class="hljs-comment">//i用来指向部分匹配字符串末尾的字符，j用来指向开始的字符</span>
      <span class="hljs-keyword">for</span>(<span class="hljs-keyword">int</span> i = <span class="hljs-number">1</span>, j = <span class="hljs-number">0</span>; i&lt;matchStr.length(); i++) &#123;
         <span class="hljs-comment">//当j&gt;0且前缀后缀不匹配时，使用部分匹配表中前一个表项的值</span>
         <span class="hljs-keyword">while</span> (j &gt; <span class="hljs-number">0</span> &amp;&amp; matchStr.charAt(j) != matchStr.charAt(i)) &#123;
            j = sectionTable[j-<span class="hljs-number">1</span>];
         &#125;

         <span class="hljs-comment">//如果前缀后缀匹配，j向后移，继续比较</span>
         <span class="hljs-keyword">if</span>(matchStr.charAt(j) == matchStr.charAt(i)) &#123;
            j++;
         &#125;
         <span class="hljs-comment">//存入匹配值</span>
         sectionTable[i] = j;
      &#125;
      <span class="hljs-keyword">return</span> sectionTable;
   &#125;

   <span class="hljs-comment">/**</span>
<span class="hljs-comment">    * 通过KMP算法匹配字符串，若匹配成功，返回第一个字符出现的位置</span>
<span class="hljs-comment">    *</span>
<span class="hljs-comment">    * <span class="hljs-doctag">@param</span> str1 用于匹配的字符串</span>
<span class="hljs-comment">    * <span class="hljs-doctag">@param</span> str2 要匹配的字符串</span>
<span class="hljs-comment">    * <span class="hljs-doctag">@return</span> 第一个字符出现的位置，没有则返回-1</span>
<span class="hljs-comment">    */</span>
   <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">static</span> <span class="hljs-keyword">int</span> <span class="hljs-title">getPosition</span><span class="hljs-params">(String str1, String str2)</span> </span>&#123;
      <span class="hljs-comment">//获得str2的部分匹配表</span>
      <span class="hljs-keyword">int</span>[] sectionTable = getTable(str2);
      <span class="hljs-keyword">for</span>(<span class="hljs-keyword">int</span> i = <span class="hljs-number">0</span>, j = <span class="hljs-number">0</span>; i &lt; str1.length(); i++) &#123;
         <span class="hljs-comment">//两个字符匹配</span>
         <span class="hljs-keyword">if</span>(str1.charAt(i) == str2.charAt(j)) &#123;
            j++;
            <span class="hljs-keyword">if</span>(j == str2.length()) &#123;
               <span class="hljs-comment">//如果匹配完成，返回第一个字符出现位置</span>
               <span class="hljs-keyword">return</span> i - str2.length() + <span class="hljs-number">1</span>;
            &#125;
         &#125; <span class="hljs-keyword">else</span> &#123;
            <span class="hljs-comment">//如果匹配失败了，使用部分匹配表，跳转到str1对应位置</span>
            <span class="hljs-comment">//如果j==0，说明没有字符被被匹配，直接让i指向str1的下一个字符</span>
            <span class="hljs-keyword">if</span>(j == <span class="hljs-number">0</span>) &#123;
               <span class="hljs-keyword">continue</span>;
            &#125;
            <span class="hljs-comment">//跳转步数 = 已经匹配的字符个数 - 部分匹配表对应的值</span>
            <span class="hljs-keyword">int</span> position = j - sectionTable[j-<span class="hljs-number">1</span>];
            i += position;
            <span class="hljs-comment">//因为循环后会+1，所以此处i-1</span>
            i--;
            <span class="hljs-comment">//重置j，重新匹配</span>
            j = <span class="hljs-number">0</span>;
         &#125;
      &#125;
      <span class="hljs-keyword">return</span> -<span class="hljs-number">1</span>;
   &#125;
&#125;</code></pre>



<p><strong>运行结果</strong></p>
<pre><code class="hljs angelscript">匹配位置是：str1[<span class="hljs-number">15</span>]</code></pre>



<h2 id="4、贪心算法"><a href="#4、贪心算法" class="headerlink" title="4、贪心算法"></a>4、贪心算法</h2><h3 id="算法简介"><a href="#算法简介" class="headerlink" title="算法简介"></a>算法简介</h3><ul>
<li>贪心算法(贪心算法)是指在对问题进行求解时，<strong>在每一步选择中都采取最好或者最优</strong>（即最有利)的选择，从而</li>
</ul>
<p><strong>希望能够导致结果是最好或者最优的算法</strong></p>
<ul>
<li>贪心算法所得到的结果<strong>不一定</strong>是最优的结果(有时候会是最优解)，但是都是<strong>相对近似</strong>(接近)最优解的结果</li>
</ul>
<h3 id="算法应用——集合覆盖"><a href="#算法应用——集合覆盖" class="headerlink" title="算法应用——集合覆盖"></a>算法应用——集合覆盖</h3><p>假设存在下面需要付费的广播台，以及广播台信号可以覆盖的地区。如何选择最少的广播台，让所有的地区都可以接收到信号</p>
<table>
<thead>
<tr>
<th>电台</th>
<th>覆盖地区个数</th>
<th>覆盖地区</th>
</tr>
</thead>
<tbody><tr>
<td>K1</td>
<td>0</td>
<td>北京 上海 天津</td>
</tr>
<tr>
<td>K2</td>
<td>0</td>
<td>广州 北京 深圳</td>
</tr>
<tr>
<td>K3</td>
<td>0</td>
<td>成都 上海 杭州</td>
</tr>
<tr>
<td>K4</td>
<td>0</td>
<td>上海 天津</td>
</tr>
<tr>
<td>K5</td>
<td>0</td>
<td>杭州 大连</td>
</tr>
</tbody></table>
<h4 id="思路及图解-1"><a href="#思路及图解-1" class="headerlink" title="思路及图解"></a>思路及图解</h4><p><strong>思路</strong></p>
<ul>
<li><p>遍历所有的广播电台, 找到一个覆盖了最多未覆盖的地区的电台(此电台可能包含一些已覆盖的地区，但没有关系</p>
</li>
<li><p>将这个电台加入到一个集合中(比如 ArrayList), 想办法把该电台覆盖的地区在下次比较时去掉。</p>
</li>
<li><p>重复第 1步<strong>直到覆盖了全部的</strong>地区</p>
</li>
</ul>
<p><strong>图解</strong></p>
<p><img src="https://nyimapicture.oss-cn-beijing.aliyuncs.com/img/20200804125936.png" srcset="/img/loading.gif" alt=""></p>
<ul>
<li>遍历电台的覆盖地区，发现K1覆盖的地区最多，将K1覆盖的地区从地区集合中移除。然后将K1放入电台集合中，并更新覆盖地区个数</li>
</ul>
<p><img src="https://nyimapicture.oss-cn-beijing.aliyuncs.com/img/20200804130058.png" srcset="/img/loading.gif" alt=""></p>
<ul>
<li>遍历，发现K2覆盖的地区最多，将K2覆盖的地区从地区集合中移除。然后将K2放入电台集合中，并更新覆盖地区个数</li>
</ul>
<p><img src="https://nyimapicture.oss-cn-beijing.aliyuncs.com/img/20200804130307.png" srcset="/img/loading.gif" alt=""></p>
<ul>
<li>遍历，发现K3覆盖的地区最多，将K3覆盖的地区从地区集合中移除。然后将K3放入电台集合中，并更新覆盖地区个数</li>
</ul>
<p><img src="https://nyimapicture.oss-cn-beijing.aliyuncs.com/img/20200804130445.png" srcset="/img/loading.gif" alt=""></p>
<ul>
<li>遍历，发现K5覆盖的地区最多，将K5覆盖的地区从地区集合中移除。然后将K5放入电台集合中，并更新覆盖地区个数。所有区域都被覆盖，算法结束</li>
</ul>
<p><img src="https://nyimapicture.oss-cn-beijing.aliyuncs.com/img/20200804130608.png" srcset="/img/loading.gif" alt=""></p>
<h3 id="算法应用——钱币找零"><a href="#算法应用——钱币找零" class="headerlink" title="算法应用——钱币找零"></a>算法应用——钱币找零</h3><p>假设纸币金额为1元、5元、10元、20元、50元、100元</p>
<p>要凑成123元应该尽可能兑换少的纸币</p>
<h4 id="算法思路"><a href="#算法思路" class="headerlink" title="算法思路"></a>算法思路</h4><ul>
<li>尽可能从大面值一直往下减即可</li>
</ul>
<h4 id="实现代码-13"><a href="#实现代码-13" class="headerlink" title="实现代码"></a>实现代码</h4><pre><code class="hljs java"><span class="hljs-keyword">public</span> <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">Demo1</span> </span>&#123;
   <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">static</span> <span class="hljs-keyword">void</span> <span class="hljs-title">main</span><span class="hljs-params">(String[] args)</span> </span>&#123;
      splitChange(<span class="hljs-number">123</span>);
   &#125;

   <span class="hljs-comment">/**</span>
<span class="hljs-comment">    * 拆分零钱</span>
<span class="hljs-comment">    *</span>
<span class="hljs-comment">    * <span class="hljs-doctag">@param</span> money 钱币总金额</span>
<span class="hljs-comment">    */</span>
   <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">static</span> <span class="hljs-keyword">void</span> <span class="hljs-title">splitChange</span><span class="hljs-params">(<span class="hljs-keyword">int</span> money)</span> </span>&#123;
      <span class="hljs-comment">//零钱金额，纸币的种类</span>
      <span class="hljs-keyword">int</span>[] prices = &#123;<span class="hljs-number">100</span>, <span class="hljs-number">50</span>, <span class="hljs-number">20</span>, <span class="hljs-number">10</span>, <span class="hljs-number">5</span>, <span class="hljs-number">1</span>&#125;;
      <span class="hljs-comment">//用于记录每种纸币的数量，下标与prices数组的下标对应</span>
      <span class="hljs-keyword">int</span>[] counts = <span class="hljs-keyword">new</span> <span class="hljs-keyword">int</span>[prices.length];
      <span class="hljs-comment">//剩下的金额</span>
      <span class="hljs-keyword">int</span> surplus = money;
      <span class="hljs-keyword">if</span>(money &gt; <span class="hljs-number">0</span>) &#123;
         <span class="hljs-comment">//如果剩下的金额大于0</span>
         <span class="hljs-keyword">while</span>(surplus &gt; <span class="hljs-number">0</span>) &#123;
            <span class="hljs-comment">//从大金额向小金额进行凑数</span>
            <span class="hljs-keyword">for</span>(<span class="hljs-keyword">int</span> i = <span class="hljs-number">0</span>; i&lt;prices.length; i++) &#123;
               <span class="hljs-comment">//每张钱币的数量</span>
               <span class="hljs-keyword">int</span> count = <span class="hljs-number">0</span>;
               <span class="hljs-comment">//如果该金额的钱币小于总金额，该钱币数量+1</span>
               <span class="hljs-keyword">while</span> (surplus - prices[i] &gt;= <span class="hljs-number">0</span>) &#123;
                  count++;
                  surplus -= prices[i];
               &#125;
               counts[i] = count;
            &#125;
         &#125;
      &#125;


      <span class="hljs-comment">//打印结果</span>
      System.out.println(<span class="hljs-string">"凑成"</span> + money +<span class="hljs-string">"元"</span>);
      <span class="hljs-keyword">for</span>(<span class="hljs-keyword">int</span> i = <span class="hljs-number">0</span>; i&lt;prices.length; i++) &#123;
         <span class="hljs-keyword">if</span>(counts[i] != <span class="hljs-number">0</span>) &#123;
            System.out.println(<span class="hljs-string">"需要"</span> + prices[i] + <span class="hljs-string">"元的纸币"</span> + counts[i] + <span class="hljs-string">"张"</span>);
         &#125;
      &#125;
   &#125;
&#125;</code></pre>



<p><strong>运行结果</strong></p>
<pre><code class="hljs angelscript">凑成<span class="hljs-number">123</span>元
需要<span class="hljs-number">100</span>元的纸币<span class="hljs-number">1</span>张
需要<span class="hljs-number">20</span>元的纸币<span class="hljs-number">1</span>张
需要<span class="hljs-number">1</span>元的纸币<span class="hljs-number">3</span>张</code></pre>


            </article>
            <hr>
            <div>
              <div class="post-metas mb-3">
                
                  <div class="post-meta mr-3">
                    <i class="iconfont icon-category"></i>
                    
                      <a class="hover-with-bg" href="/categories/Java/">Java</a>
                    
                  </div>
                
                
                  <div class="post-meta">
                    <i class="iconfont icon-tags"></i>
                    
                      <a class="hover-with-bg" href="/tags/%E6%95%B0%E6%8D%AE%E7%BB%93%E6%9E%84%E4%B8%8E%E7%AE%97%E6%B3%95/">数据结构与算法</a>
                    
                  </div>
                
              </div>
              
                <p class="note note-warning">本博客所有文章除特别声明外，均采用 <a href="https://creativecommons.org/licenses/by-sa/4.0/deed.zh" target="_blank" rel="nofollow noopener noopener">CC BY-SA 4.0 协议</a> ，转载请注明出处！</p>
              
              
                <div class="post-prevnext row">
                  <div class="post-prev col-6">
                    
                    
                      <a href="/2020/07/03/JVM%E5%AD%A6%E4%B9%A0/">
                        <i class="iconfont icon-arrowleft"></i>
                        <span class="hidden-mobile">JVM</span>
                        <span class="visible-mobile">Previous</span>
                      </a>
                    
                  </div>
                  <div class="post-next col-6">
                    
                    
                      <a href="/2020/06/08/%E5%B9%B6%E5%8F%91%E7%BC%96%E7%A8%8B/">
                        <span class="hidden-mobile">Java并发</span>
                        <span class="visible-mobile">Next</span>
                        <i class="iconfont icon-arrowright"></i>
                      </a>
                    
                  </div>
                </div>
              
            </div>

            
              <!-- Comments -->
              <div class="comments" id="comments">
                
                
  <div class="disqus" style="width:100%">
    <div id="disqus_thread"></div>
    <script type="text/javascript">
      function loadDisqus() {
        var disqus_config = function () {
          this.page.url = 'http://nyimac.gitee.io/2020/06/17/数据结构与算法/';
          this.page.identifier = '/2020/06/17/数据结构与算法/';
        };
        (function () {
          var d = document,
            s = d.createElement('script');
          s.src = '//' + '' + '.disqus.com/embed.js';
          s.setAttribute('data-timestamp', new Date());
          (d.head || d.body).appendChild(s);
        })();
      }
      createObserver(loadDisqus, 'disqus_thread');
    </script>
    <noscript>Please enable JavaScript to view the
      <a href="https://disqus.com/?ref_noscript" target="_blank" rel="nofollow noopener noopener">comments powered by Disqus.</a>
    </noscript>
  </div>


              </div>
            
          </div>
        </div>
      </div>
    </div>
    
      <div class="d-none d-lg-block col-lg-2 toc-container" id="toc-ctn">
        <div id="toc">
  <p class="toc-header"><i class="iconfont icon-list"></i>&nbsp;TOC</p>
  <div id="tocbot"></div>
</div>

      </div>
    
  </div>
</div>

<!-- Custom -->


    
  </main>

  
    <a id="scroll-top-button" href="#" role="button">
      <i class="iconfont icon-arrowup" aria-hidden="true"></i>
    </a>
  

  
    <div class="modal fade" id="modalSearch" tabindex="-1" role="dialog" aria-labelledby="ModalLabel"
     aria-hidden="true">
  <div class="modal-dialog modal-dialog-scrollable modal-lg" role="document">
    <div class="modal-content">
      <div class="modal-header text-center">
        <h4 class="modal-title w-100 font-weight-bold">Search</h4>
        <button type="button" id="local-search-close" class="close" data-dismiss="modal" aria-label="Close">
          <span aria-hidden="true">&times;</span>
        </button>
      </div>
      <div class="modal-body mx-3">
        <div class="md-form mb-5">
          <input type="text" id="local-search-input" class="form-control validate">
          <label data-error="x" data-success="v"
                 for="local-search-input">keyword</label>
        </div>
        <div class="list-group" id="local-search-result"></div>
      </div>
    </div>
  </div>
</div>
  

  

  

  <footer class="mt-5">
  <div class="text-center py-3">
    <div>
      <a href="https://hexo.io" target="_blank" rel="nofollow noopener"><span>Hexo</span></a>
      <i class="iconfont icon-love"></i>
      <a href="https://github.com/fluid-dev/hexo-theme-fluid" target="_blank" rel="nofollow noopener">
        <span>Fluid</span></a>
    </div>
    
  <div class="statistics">
    
    

    
      
        <!-- 不蒜子统计PV -->
        <span id="busuanzi_container_site_pv" style="display: none">
            总访问量 
            <span id="busuanzi_value_site_pv"></span>
             次
          </span>
      
      
        <!-- 不蒜子统计UV -->
        <span id="busuanzi_container_site_uv" style="display: none">
            总访客数 
            <span id="busuanzi_value_site_uv"></span>
             人
          </span>
      
    
  </div>


    

    
  </div>
</footer>

<!-- SCRIPTS -->
<script  src="https://cdn.staticfile.org/jquery/3.4.1/jquery.min.js" ></script>
<script  src="https://cdn.staticfile.org/twitter-bootstrap/4.4.1/js/bootstrap.min.js" ></script>
<script  src="/js/debouncer.js" ></script>
<script  src="/js/main.js" ></script>

<!-- Plugins -->


  
    <script  src="/js/lazyload.js" ></script>
  



  <script defer src="https://cdn.staticfile.org/clipboard.js/2.0.6/clipboard.min.js" ></script>
  <script  src="/js/clipboard-use.js" ></script>



  <script defer src="https://busuanzi.ibruce.info/busuanzi/2.3/busuanzi.pure.mini.js" ></script>





  <script  src="https://cdn.staticfile.org/tocbot/4.11.1/tocbot.min.js" ></script>
  <script>
    $(document).ready(function () {
      var boardCtn = $('#board-ctn');
      var boardTop = boardCtn.offset().top;

      tocbot.init({
        tocSelector: '#tocbot',
        contentSelector: 'article.markdown-body',
        headingSelector: 'h1,h2,h3,h4,h5,h6',
        linkClass: 'tocbot-link',
        activeLinkClass: 'tocbot-active-link',
        listClass: 'tocbot-list',
        isCollapsedClass: 'tocbot-is-collapsed',
        collapsibleClass: 'tocbot-is-collapsible',
        collapseDepth: 0,
        scrollSmooth: true,
        headingsOffset: -boardTop
      });
      if ($('.toc-list-item').length > 0) {
        $('#toc').css('visibility', 'visible');
      }
    });
  </script>



  <script  src="https://cdn.staticfile.org/typed.js/2.0.11/typed.min.js" ></script>
  <script>
    var typed = new Typed('#subtitle', {
      strings: [
        '  ',
        "Java数据结构与算法&nbsp;",
      ],
      cursorChar: "_",
      typeSpeed: 70,
      loop: false,
    });
    typed.stop();
    $(document).ready(function () {
      $(".typed-cursor").addClass("h2");
      typed.start();
    });
  </script>



  <script  src="https://cdn.staticfile.org/anchor-js/4.2.2/anchor.min.js" ></script>
  <script>
    anchors.options = {
      placement: "right",
      visible: "hover",
      
    };
    var el = "h1,h2,h3,h4,h5,h6".split(",");
    var res = [];
    for (item of el) {
      res.push(".markdown-body > " + item)
    }
    anchors.add(res.join(", "))
  </script>



  <script  src="/js/local-search.js" ></script>
  <script>
    var path = "/local-search.xml";
    var inputArea = document.querySelector("#local-search-input");
    inputArea.onclick = function () {
      searchFunc(path, 'local-search-input', 'local-search-result');
      this.onclick = null
    }
  </script>



  <script  src="https://cdn.staticfile.org/fancybox/3.5.7/jquery.fancybox.min.js" ></script>
  <link  rel="stylesheet" href="https://cdn.staticfile.org/fancybox/3.5.7/jquery.fancybox.min.css" />

  <script>
    $('#post img:not(.no-zoom img, img[no-zoom]), img[zoom]').each(
      function () {
        var element = document.createElement('a');
        $(element).attr('data-fancybox', 'images');
        $(element).attr('href', $(this).attr('src'));
        $(this).wrap(element);
      }
    );
  </script>

















  
    <!-- Baidu Analytics -->
    <script defer>
      var _hmt = _hmt || [];
      (function () {
        var hm = document.createElement("script");
        hm.src = "https://hm.baidu.com/hm.js?ba41ec605b9b7320e120275462e4035b";
        var s = document.getElementsByTagName("script")[0];
        s.parentNode.insertBefore(hm, s);
      })();
    </script>
  

  

  

  

  

  





</body>
</html>
